安卓线程池ThreadPoolExecutor的常见使用
Posted z8z87878
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓线程池ThreadPoolExecutor的常见使用相关的知识,希望对你有一定的参考价值。
烦躁的时候不应该把气撒在对我们好的人身上
为什么要用线程池呢,这个东西好处一大堆是吧….额,线程池帮我们管理线程,它会帮我们创建定制的线程进行复用,防止老new浪费资源造成内存碎片之类,等等.总之就是效率好,资源利用好,公认的好.可以说没有线程池的应用都是那种……对吧.嗯.来看看线程池执行者这个类吧,ThreadPoolExecutor,通过它我们可以创建我们的线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize, //核心线程数
maximumPoolSize, //最大线程数
keepAliveTime, //空闲线程存活时间
unit, //存活时间单位
workQueue, //缓存工作队列
threadFacory, //线程工厂,用来创建线程
hander //添加任务产生的异常//
);
额,我在这解释一下这几个参数之间的关系吧.嗯,还是先看看效果比较好说
public class MainActivity extends Activity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int corePoolSize = 3;
int maximumPoolSize = 4;
long keepAliveTime = 3000;
TimeUnit unit = TimeUnit.MILLISECONDS;//毫秒
BlockingQueue<Runnable> workQueue = new LinkedBlockingDeque<Runnable>(1);
ThreadFactory threadFacory = Executors.defaultThreadFactory();
RejectedExecutionHandler hander = new ThreadPoolExecutor.AbortPolicy();
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize, //核心线程数
maximumPoolSize, //最大线程数
keepAliveTime, //空闲线程存活时间
unit, //存活时间单位
workQueue, //缓存工作队列
threadFacory, //线程工厂,用来创建线程
hander //添加任务产生的异常//
);
executor.execute(new MyTask());
executor.execute(new MyTask());
executor.execute(new MyTask());
executor.execute(new MyTask());
executor.execute(new MyTask());
executor.execute(new MyTask());
class MyTask implements Runnable
@Override
public void run()
Log.d("MyTask", "线程池测试");
SystemClock.sleep(3000);
//输出
06-27 04:04:55.731 6591-6616/com.it.threadpollnotes D/MyTask: 线程池测试
06-27 04:04:55.735 6591-6617/com.it.threadpollnotes D/MyTask: 线程池测试
06-27 04:04:55.735 6591-6620/com.it.threadpollnotes D/MyTask: 线程池测试
06-27 04:04:55.739 6591-6591/com.it.threadpollnotes D/androidRuntime: Shutting down VM
06-27 04:04:55.739 6591-6591/com.it.threadpollnotes W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0xa4ca5b20)
06-27 04:04:55.751 6591-6621/com.it.threadpollnotes D/MyTask: 线程池测试
06-27 04:04:55.759 6591-6591/com.it.threadpollnotes E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.it.threadpollnotes, PID: 6591
java.lang.RuntimeException: Unable to start activity ComponentInfocom.it.threadpollnotes/com.it.threadpollnotes.MainActivity: java.util.concurrent.RejectedExecutionException: Task com.it.threadpollnotes.MainActivity$MyTask@527ef2e4 rejected from java.util.concurrent.ThreadPoolExecutor@527eee78[Running, pool size = 4, active threads = 4, queued tasks = 1, completed tasks = 0]
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2184)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
at android.app.ActivityThread.access$800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.util.concurrent.RejectedExecutionException: Task com.it.threadpollnotes.MainActivity$MyTask@527ef2e4 rejected from java.util.concurrent.ThreadPoolExecutor@527eee78[Running, pool size = 4, active threads = 4, queued tasks = 1, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2011)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:793)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1339)
at com.it.threadpollnotes.MainActivity.onCreate(MainActivity.java:47)
at android.app.Activity.performCreate(Activity.java:5231)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
at android.app.ActivityThread.access$800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
06-27 04:04:58.735 6591-6617/com.it.threadpollnotes D/MyTask: 线程池测试
06-27 04:05:43.054 7207-7223/com.it.threadpollnotes D/MyTask: 线程池测试
抛异常应用给停止了,嗯.根据输出结果我们可以看到,前面是执行了四个任务,到第五个任务才抛异常的.是这样的,因为我们的核心线程数为3,即其实我们的线程池最多本来可以执行三个线程的,这时候来了第四个任务,我们把它放入我们的缓存队列.我们的缓存队列我给它设置了大小为1,即它只可以放一个缓存任务,这时候第五个任务来了.核心线程满了,缓存队列也满了,它就看最大线程数,这时候,发现最大线程数是4,即线程池会去创建个新的线程去执行这个任务.如果这时候没有任务来的话,且缓存队列中的线程也工作完了,还有这四个工作的线程有一个停止了工作,即处于空闲状态的话,我们的keepAliveTime就开始工作了,到了设定的时间,该线程还处于空闲的话,就会被我们的线程池回收到只剩下三个线程.即我们的核心线程数.但是这个时候我们四个线程正在工作,不处于空闲状态,缓存队列也满了,因为它只能放一个.这时候第六个任务来了,它先去找核心线程,看能不能执行它,发现不行,再去找缓存队列,能不能收留它,还发现不行,接着它再去看最大线程数,求它为它创建个新线程.但是最大线程也满了.这时候悲剧了,它不好过,它也不让你们好过.因为hander = new ThreadPoolExecutor.AbortPolicy();它就直接自爆了,抛了这个异常.应用就挂掉了.嗯,这就是线程池一般的运行机制,当然我们造线程池当然不会这么造.这里说下几个参数的常见设置,核心线程,最大线程,存活时间,时间单位,我们先跳过,先来看看缓存工作队列workQueue
它的参数类型是BlockingQueue它是一个接口,我们看一下它有哪些实现类
我们这介绍这几个:
* ArrayBlockingQueue(有界队列)`: FIFO 队列,规定大小的BlockingQueue,其构造函数必须带一个int参数来指明其大小
LinkedBlockingQueue(无界队列)`:FIFO 队列,大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定。
PriorityBlockingQueue`:优先级队列, 类似于LinkedBlockingQueue,但队列中元素非 FIFO, 依据对象的自然排序顺序或者是构造函数所带的Comparator决定的顺序
SynchronousQueue(直接提交策略)`: 交替队列,队列中操作时必须是先放进去,接着取出来,交替着去处理元素的添加和移除
我们一般都使用LinkedBlockingQueue(无界队列),AsnycTask中用的也是这个,我们可以把它设置为无界的,即不传参数.这就不用担心创建了很多任务挂了.不过AsnycTask在23的SDK中设置的是128个,所以一般都达不到的.
接着我们来看线程工程threadFacory,线程工厂,Executors的一个内部类实现了它ThreadFactory,Executors是一个比较强的类,它还可以给我们创建一下简单的线程池,当然它也是基于ThreadPoolExecutor实现的
最后一个参数RejectedExecutionHandler hander,它是一个接口,它的实现类有
ThreadPoolExecutor.AbortPolicy
当添加任务出错时的策略捕获器,如果出现错误,则直接抛出异常
ThreadPoolExecutor.CallerRunsPolicy
当添加任务出错时的策略捕获器,如果出现错误,直接执行加入的任务
ThreadPoolExecutor.DiscardOldestPolicy
当添加任务出错时的策略捕获器,如果出现错误,移除第一个任务,执行加入的任务
ThreadPoolExecutor.DiscardPolicy
当添加任务出错时的策略捕获器,如果出现错误,不做处理
好啦,差不多就讲完了吧.核心线程数和最大线程数,存活时间,我们去看看AsyncTask是怎么写的
rivate static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
即如果工作的CPU是双核的,它设置的是核心线程数是3,最大线程数是5,存活时间是1秒.当然我们可以根据自己的要求自己定制自己的线程池,额,最后再来看看这两个方法
executor.submit(Runnable task); //提交任务,和execute一样是执行,区别不大...它返回一个Future<?> future可以用来判断任务有没有执行成功,有些时候用得上
executor.remove(Runnable task);//移除任务
如果future.get()==null的话,说明任务执行成功.如果我们的RejectedExecutionHandler hander设置的不是出错抛异常的话,还是用的上的.所以一般都用submit这个方法
以上是关于安卓线程池ThreadPoolExecutor的常见使用的主要内容,如果未能解决你的问题,请参考以下文章