正文
第三个参数的单位,有纳秒、微秒、毫秒、秒、分、时、天等
workQueue
线程池中的任务队列,该队列主要用来存储已经被提交但是尚未执行的任务。存储在这里的任务是由ThreadPoolExecutor的execute方法提交来的。
threadFactory
为线程池提供创建新线程的功能,这个我们一般使用默认即可
handler
拒绝策略,当线程无法执行新任务时(一般是由于线程池中的线程数量已经达到最大数或者线程池关闭导致的),默认情况下,当线程池无法处理新线程时,会抛出一个RejectedExecutionException。
针对于workQueue参数我多说几点:workQueue是一个BlockingQueue类型,那么这个BlockingQueue又是什么呢?它是一个特殊的队列,当我们从BlockingQueue中取数据时,如果BlockingQueue是空的,则取数据的操作会进入到阻塞状态,当BlockingQueue中有了新数据时,这个取数据的操作又会被重新唤醒。同理,如果BlockingQueue中的数据已经满了,往BlockingQueue中存数据的操作又会进入阻塞状态,直到BlockingQueue中又有新的空间,存数据的操作又会被冲洗唤醒。BlockingQueue有多种不同的实现类,下面我举几个例子来说一下:
1.ArrayBlockingQueue
:这个表示一个规定了大小的BlockingQueue,ArrayBlockingQueue的构造函数接受一个int类型的数据,该数据表示BlockingQueue的大小,存储在ArrayBlockingQueue中的元素按照FIFO(先进先出)的方式来进行存取。
2.LinkedBlockingQueue:
这个表示一个大小不确定的BlockingQueue,在LinkedBlockingQueue的构造方法中可以传一个int类型的数据,这样创建出来的LinkedBlockingQueue是有大小的,也可以不传,不传的话,LinkedBlockingQueue的大小就为Integer.MAX_VALUE,源码如下:
3.PriorityBlockingQueue:
这个队列和LinkedBlockingQueue类似,不同的是PriorityBlockingQueue中的元素不是按照FIFO来排序的,而是按照元素的Comparator来决定存取顺序的(这个功能也反映了存入PriorityBlockingQueue中的数据必须实现
了Comparator接口)。
4.SynchronousQueue:
这个是同步Queue,属于线程安全的BlockingQueue的一种,在SynchronousQueue中,生产者线程的插入操作必须要等待消费者线程的移除操作,Synchronous内部没有数据缓存空间,因此我们无法对SynchronousQueue进行读取或者遍历其中的数据,元素只有在你试图取走的时候才有可能存在。我们可以理解为生产者和消费者互相等待,等到对方之后然后再一起离开。
OK,这是ThreadPoolExecutor的构造方法参数的解释,我们的线程提交到线程池之后又是按照什么样的规则去运行呢?OK,它们遵循如下规则:
1.execute一个线程之后,如果线程池中的线程数未达到核心线程数,则会立马启用一个核心线程去执行
2.execute一个线程之后,如果线程池中的线程数已经达到核心线程数,加小遍微信:AMEPRE。且workQueue未满,则将新线程放入workQueue中等待执行
3.execute一个线程之后,如果线程池中的线程数已经达到核心线程数但未超过非核心线程数,且workQueue已满,则开启一个非核心线程来执行任务
4.execute一个线程之后,如果线程池中的线程数已经超过非核心线程数,则拒绝执行该任务
OK,基于以上讲解,我们来看一个Demo:
执行结果如下:
OK,由于核心线程数为3,workQueue的大小为128,所以我们的线程的执行应该是先启动三个核心线程来执行任务,剩余的27个任务全部存在workQueue中,等待核心线程空余出来之后执行。OK,那我把构造ThreadPoolExecutor的参数修改一下,来验证一下我们上面的结论正确与否:
如上,我把最大线程数改为30,而把线程队列大小改为6(实际开发中 不会这样来设置,这里只是为了验证结论),我们来看看执行结果:
(动态图片可点击阅读原文查看)
OK,首先打印出来0,1,2说明往核心线程添加了三个任务,然后将3,4,5,6,7,8六个任务添加到了任务队列中,接下来要添加的任务因为核心线程已满,队列已满所以就直接开一个非核心线程来执行,因此后添加的任务反而会先执行(3,4,5,6,7,8都在队列中等着),所以我们看到的打印结果是先是0~2,然后9~29,然后3~8,当然,我们在实际开发中不会这样来配置最大线程数和线程队列。那如果我们需要自己来配置这些参数,该如何配置呢?参考一下AsyncTask,AsyncTask部分源码如下: