优秀网站页面设计图片,wordpress用户增加插件,龙华网站建设首页地址,佛山抖音seo介绍new Thread的弊端及Java四种线程池的使用#xff0c;对Android同样适用。本文是基础篇#xff0c;后面会分享下线程池一些高级功能。 1、new Thread的弊端 执行一个异步任务你还只是如下new Thread吗#xff1f; new Thread(new Runnable() {Overridepublic void run() …
介绍new Thread的弊端及Java四种线程池的使用对Android同样适用。本文是基础篇后面会分享下线程池一些高级功能。 1、new Thread的弊端 执行一个异步任务你还只是如下new Thread吗 new Thread(new Runnable() {Overridepublic void run() {// TODO Auto-generated method stub}
}).start(); 那你就out太多了new Thread的弊端如下 a. 每次new Thread新建对象性能差。 b. 线程缺乏统一管理可能无限制新建线程相互之间竞争及可能占用过多系统资源导致死机或oom。 c. 缺乏更多功能如定时执行、定期执行、线程中断。 相比new ThreadJava提供的四种线程池的好处在于 a. 重用存在的线程减少对象创建、消亡的开销性能佳。 b. 可有效控制最大并发线程数提高系统资源的使用率同时避免过多资源竞争避免堵塞。 c. 提供定时执行、定期执行、单线程、并发数控制等功能。 2、Java 线程池 Java通过Executors提供四种线程池分别为 newCachedThreadPool创建一个可缓存线程池如果线程池长度超过处理需要可灵活回收空闲线程若无可回收则新建线程。 newFixedThreadPool 创建一个定长线程池可控制线程最大并发数超出的线程会在队列中等待。 newScheduledThreadPool 创建一个定长线程池支持定时及周期性任务执行。 newSingleThreadExecutor 创建一个单线程化的线程池它只会用唯一的工作线程来执行任务保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。 (1). newCachedThreadPool 创建一个可缓存线程池如果线程池长度超过处理需要可灵活回收空闲线程若无可回收则新建线程。示例代码如下 ExecutorService cachedThreadPool Executors.newCachedThreadPool();
for (int i 0; i 10; i) {final int index i;try {Thread.sleep(index * 1000);} catch (InterruptedException e) {e.printStackTrace();}cachedThreadPool.execute(new Runnable() {Overridepublic void run() {System.out.println(index);}});
} 线程池为无限大当执行第二个任务时第一个任务已经完成会复用执行第一个任务的线程而不用每次新建线程。 (2). newFixedThreadPool 创建一个定长线程池可控制线程最大并发数超出的线程会在队列中等待。示例代码如下 ExecutorService fixedThreadPool Executors.newFixedThreadPool(3);
for (int i 0; i 10; i) {final int index i;fixedThreadPool.execute(new Runnable() {Overridepublic void run() {try {System.out.println(index);Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});
} 因为线程池大小为3每个任务输出index后sleep 2秒所以每两秒打印3个数字。 定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()。可参考PreloadDataCache。 (3) newScheduledThreadPool 创建一个定长线程池支持定时及周期性任务执行。延迟执行示例代码如下 ScheduledExecutorService scheduledThreadPool Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {Overridepublic void run() {System.out.println(delay 3 seconds);}
}, 3, TimeUnit.SECONDS); 表示延迟3秒执行。 定期执行示例代码如下 scheduledThreadPool.scheduleAtFixedRate(new Runnable() {Overridepublic void run() {System.out.println(delay 1 seconds, and excute every 3 seconds);}
}, 1, 3, TimeUnit.SECONDS); 表示延迟1秒后每3秒执行一次。 ScheduledExecutorService比Timer更安全功能更强大后面会有一篇单独进行对比。 (4)、newSingleThreadExecutor 创建一个单线程化的线程池它只会用唯一的工作线程来执行任务保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下 ExecutorService singleThreadExecutor Executors.newSingleThreadExecutor();
for (int i 0; i 10; i) {final int index i;singleThreadExecutor.execute(new Runnable() {Overridepublic void run() {try {System.out.println(index);Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});
} 结果依次输出相当于顺序执行各个任务。 现行大多数GUI程序都是单线程的。Android中单线程可用于数据库操作文件操作应用批量安装应用批量删除等不适合并发但可能IO阻塞性及影响UI线程响应的操作。 3. 实例演示Android异步加载图片 给大家演示异步加载图片的分析过程。让大家了解异步加载图片的好处以及如何更新UI。 首先给出main.xml布局文件 简单来说就是 LinearLayout 布局其下放了2个TextView和5个ImageView。 ?xml version1.0 encodingutf-8?
LinearLayoutxmlns:androidhttp://schemas.android.com/apk/res/androidandroid:orientationverticalandroid:layout_widthfill_parentandroid:layout_heightfill_parentTextViewandroid:text图片区域开始android:idid/textView2android:layout_widthwrap_contentandroid:layout_heightwrap_content /ImageViewandroid:idid/imageView1android:layout_heightwrap_contentandroid:srcdrawable/iconandroid:layout_widthwrap_content /ImageViewandroid:idid/imageView2android:layout_heightwrap_contentandroid:srcdrawable/iconandroid:layout_widthwrap_content /ImageViewandroid:idid/imageView3android:layout_heightwrap_contentandroid:srcdrawable/iconandroid:layout_widthwrap_content /ImageViewandroid:idid/imageView4android:layout_heightwrap_contentandroid:srcdrawable/iconandroid:layout_widthwrap_content /ImageViewandroid:idid/imageView5android:layout_heightwrap_contentandroid:srcdrawable/iconandroid:layout_widthwrap_content /TextViewandroid:text图片区域结束android:idid/textView1android:layout_widthwrap_contentandroid:layout_heightwrap_content /
/LinearLayout 我们将演示的过程是异步从服务器上下载5张不同图片依次放入这5个ImageView。上下2个TextView 是为了方便我们看是否阻塞了UI的显示。 当然 AndroidManifest.xml 文件中要配置好网络访问权限。 uses-permission android:nameandroid.permission.INTERNET / 1)HandlerRunnable模式 我们先看一个并不是异步线程加载的例子而是使用 HandlerRunnable模式。 注意这里不是新开的线程这里的代码其实是在UI主线程中下载图片的。 我们运行下面代码时会发现它其实是阻塞了整个界面的显示需要所有图片都加载完成后才能显示界面。 package com.szy.textviewimagedemo;import java.io.IOException;
import java.net.URL;import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.widget.ImageView;/***author coolszy*date 2012-2-13*blog http://blog.92coding.com**/
public class MainActivity extends Activity
{Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);loadImage(http://www.baidu.com/img/baidu_logo.gif, R.id.imageView1);loadImage(http://www.chinatelecom.com.cn/images/logo_new.gif, R.id.imageView2);loadImage(http://cache.soso.com/30d/img/web/logo.gif, R.id.imageView3);loadImage(http://csdnimg.cn/www/images/csdnindex_logo.gif, R.id.imageView4);loadImage(http://images.cnblogs.com/logo_small.gif, R.id.imageView5);}private Handler handler new Handler();private void loadImage(final String url, final int id){handler.post(new Runnable(){public void run(){Drawable drawable null;try{drawable Drawable.createFromStream(new URL(url).openStream(), image.gif);} catch (IOException e){Log.i(MainActivity, e.getMessage());}if (drawable null){Log.i(MainActivity, null drawable);} else{Log.i(MainActivity, not null drawable);}// 为了测试缓存而模拟的网络延时SystemClock.sleep(2000);((ImageView) MainActivity.this.findViewById(id)).setImageDrawable(drawable);}});}
} 2)HandlerThreadMessage模式 这种模式使用了线程所以可以看到异步加载的效果。 核心代码 package com.szy.textviewimagedemo;import java.io.IOException;
import java.net.URL;import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.widget.ImageView;/***author coolszy*date 2012-2-13*blog http://blog.92coding.com**/
public class MainActivity extends Activity
{Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);Log.i(MainActivity, MainThread ID:Thread.currentThread().getId());loadImage(http://www.baidu.com/img/baidu_logo.gif, R.id.imageView1);loadImage(http://www.chinatelecom.com.cn/images/logo_new.gif, R.id.imageView2);loadImage(http://cache.soso.com/30d/img/web/logo.gif, R.id.imageView3);loadImage(http://csdnimg.cn/www/images/csdnindex_logo.gif, R.id.imageView4);loadImage(http://images.cnblogs.com/logo_small.gif, R.id.imageView5);}final Handler handler new Handler(){Overridepublic void handleMessage(Message msg){Log.i(MainActivity, UpdateUIThread ID:Thread.currentThread().getId());((ImageView) MainActivity.this.findViewById(msg.arg1)).setImageDrawable((Drawable) msg.obj);}};// 采用handlerThread模式实现多线程异步加载private void loadImage(final String url, final int id){Thread thread new Thread(){Overridepublic void run(){Drawable drawable null;try{Log.i(MainActivity, Thread ID:Thread.currentThread().getId());drawable Drawable.createFromStream(new URL(url).openStream(), image.png);} catch (IOException e){Log.i(MainActivity, e.getMessage());}// 模拟网络延时SystemClock.sleep(2000);Message message handler.obtainMessage();message.arg1 id;message.obj drawable;handler.sendMessage(message);}};thread.start();thread null;}
} 这时候我们可以看到实现了异步加载 界面打开时五个ImageView都是没有图的然后在各自线程下载完后才把图自动更新上去。 3)HandlerExecutorService(线程池)MessageQueue模式 能开线程的个数毕竟是有限的我们总不能开很多线程对于手机更是如此。 这个例子是使用线程池。Android拥有与Java相同的ExecutorService实现我们就使用它。 线程池的基本思想还是一种对象池的思想开辟一块内存空间里面存放了众多(未死亡)的线程池中线程执行调度由池管理器来处理。当有线程任务时从池中取一个执行完成后线程对象归池这样可以避免反复创建线程对象所带来的性能开销节省了系统的资源。 下面的演示例子是创建一个可重用固定线程数的线程池。 核心代码 package com.szy.textviewimagedemo;import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.widget.ImageView;/***author coolszy*date 2012-2-13*blog http://blog.92coding.com**/
public class MainActivity extends Activity
{Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);Log.i(MainActivity, MainThread ID:Thread.currentThread().getId());loadImage(http://www.baidu.com/img/baidu_logo.gif, R.id.imageView1);loadImage(http://www.chinatelecom.com.cn/images/logo_new.gif, R.id.imageView2);loadImage(http://cache.soso.com/30d/img/web/logo.gif, R.id.imageView3);loadImage(http://csdnimg.cn/www/images/csdnindex_logo.gif, R.id.imageView4);loadImage(http://images.cnblogs.com/logo_small.gif, R.id.imageView5);}private Handler handler new Handler();private ExecutorService executorService Executors.newFixedThreadPool(5);// 引入线程池来管理多线程private void loadImage(final String url, final int id){executorService.submit(new Runnable(){public void run(){try{Log.i(MainActivity, Thread ID:Thread.currentThread().getId());final Drawable drawable Drawable.createFromStream(new URL(url).openStream(), image.png);// 模拟网络延时SystemClock.sleep(2000);handler.post(new Runnable(){public void run(){Log.i(MainActivity, UpdateUIThread ID:Thread.currentThread().getId());((ImageView) MainActivity.this.findViewById(id)).setImageDrawable(drawable);}});} catch (Exception e){throw new RuntimeException(e);}}});}
} 这里我们象第一步一样使用了 handler.post(new Runnable() { }) 更新前段显示当然是在UI主线程我们还有 executorService.submit(new Runnable() { }) 来确保下载是在线程池的线程中。 4)HandlerExecutorService(线程池)MessageQueue缓存模式 下面比起前一个做了几个改造: 把整个代码封装在一个类中同时为了避免出现同时多次下载同一幅图的问题,使用了本地缓存封装的类: package com.szy.textviewimagedemo;import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;/***author coolszy*date 2012-2-13*blog http://blog.92coding.com*/public class AsyncImageLoader
{// 为了加快速度在内存中开启缓存主要应用于重复图片较多时或者同一个图片要多次被访问比如在ListView时来回滚动public MapString, SoftReferenceDrawable imageCache new HashMapString, SoftReferenceDrawable();private ExecutorService executorService Executors.newFixedThreadPool(5); // 固定五个线程来执行任务private final Handler handler new Handler();/**** param imageUrl* 图像url地址* param callback* 回调接口* return 返回内存中缓存的图像第一次加载返回null*/public Drawable loadDrawable(final String imageUrl, final ImageCallback callback){// 如果缓存过就从缓存中取出数据if (imageCache.containsKey(imageUrl)){SoftReferenceDrawable softReference imageCache.get(imageUrl);if (softReference.get() ! null){Log.i(MainActivity, 图片存在缓存中.);return softReference.get();}}// 缓存中没有图像则从网络上取出数据并将取出的数据缓存到内存中executorService.submit(new Runnable(){public void run(){try{Log.i(MainActivity, 下载图片...);final Drawable drawable loadImageFromUrl(imageUrl);imageCache.put(imageUrl, new SoftReferenceDrawable(drawable));handler.post(new Runnable(){public void run(){callback.imageLoaded(drawable);}});} catch (Exception e){throw new RuntimeException(e);}}});return null;}// 从网络上取数据方法protected Drawable loadImageFromUrl(String imageUrl){try{// 测试时模拟网络延时实际时这行代码不能有SystemClock.sleep(2000);return Drawable.createFromStream(new URL(imageUrl).openStream(), image.png);} catch (Exception e){throw new RuntimeException(e);}}// 对外界开放的回调接口public interface ImageCallback{// 注意 此方法是用来设置目标对象的图像资源public void imageLoaded(Drawable imageDrawable);}
} 说明 final参数是指当函数参数为final类型时你可以读取使用该参数但是无法改变该参数的值。 这里使用SoftReference 是为了解决内存不足的错误OutOfMemoryError的。 前端调用: package com.szy.textviewimagedemo;import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.widget.ImageView;/***author coolszy*date 2012-2-13*blog http://blog.92coding.com**/
public class MainActivity extends Activity
{Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);loadImage(http://www.baidu.com/img/baidu_logo.gif, R.id.imageView1);loadImage(http://www.chinatelecom.com.cn/images/logo_new.gif, R.id.imageView2);loadImage(http://cache.soso.com/30d/img/web/logo.gif, R.id.imageView3);loadImage(http://csdnimg.cn/www/images/csdnindex_logo.gif, R.id.imageView4);loadImage(http://images.cnblogs.com/logo_small.gif, R.id.imageView5);}private AsyncImageLoader asyncImageLoader new AsyncImageLoader();// 引入线程池并引入内存缓存功能,并对外部调用封装了接口简化调用过程private void loadImage(final String url, final int id){// 如果缓存过就会从缓存中取出图像ImageCallback接口中方法也不会被执行Drawable cacheImage asyncImageLoader.loadDrawable(url, new AsyncImageLoader.ImageCallback(){// 请参见实现如果第一次加载url时下面方法会执行public void imageLoaded(Drawable imageDrawable){((ImageView) findViewById(id)).setImageDrawable(imageDrawable);}});if (cacheImage ! null){((ImageView) findViewById(id)).setImageDrawable(cacheImage);}}
} --------------------- 作者BrillantZhao 来源CSDN 原文https://blog.csdn.net/zhi137_zhi148_qwer/article/details/52605049 版权声明本文为作者原创文章转载请附上博文链接