Java中的线程池用ThreadPoolExecutor类来表示,ThreadPoolExecutor这个类继承自抽象类AbstractExecutorService,AbstractExecutorService又实现了ExecutorService接口,ExecutorService接口又继承了Executor接口。数组
ThreadPoolExecutor类详细说明在本博客中其余篇幅有介绍,若是须要请参考缓存
从参数即可以看到几个构造方式的不一样,可是若跟源码以后,会发现,前面三个都调用了第四个。安全
跟源码以后会发现,其实这些静态方法里面也是调用了ThreadPoolExecutor的构造方法,例如:数据结构
只不过Executors帮咱们配置了一些参数;下面介绍下Executors方式:并发
一、newCachedThreadPool 方法,它建立了一个可缓存的线程池,若是线程池的长度超过处理须要,它可灵活回收空闲线程,若无可回收,则新建线程。spa
2、newScheduledThreadPool 方法,它建立了一个定长线程池,支持定时及周期性的任务执行。线程
三、newFixedThreadPool 方法,它建立了一个定长线程池,能够控制线程最大并发数,超出的线程会在队列中等待。继承
四、newSingleThreadExecutor 方法,它建立了一个单线程化的线程池,它只会用惟一的工做线程来执行任务,保证全部的任务按照指定的顺序(FIFO, LIFO, 优先级)来执行的。接口
首先,咱们一块儿来建立一个能够缓存的线程池,若是线程池的长度超过了处理须要的话,它可灵活的回收空闲的线程,若无可回收的线程,则就新建线程。代码如图1所示:生命周期
当前线程:pool-1-thread-1输出:0
当前线程:pool-1-thread-1输出:1
当前线程:pool-1-thread-1输出:2
当前线程:pool-1-thread-1输出:3
当前线程:pool-1-thread-1输出:4
当前线程:pool-1-thread-1输出:5
当前线程:pool-1-thread-1输出:6
当前线程:pool-1-thread-1输出:7
当前线程:pool-1-thread-1输出:8
当前线程:pool-1-thread-1输出:9
以上第一种方式建立线程池,线程池为无限大的,当其执行到第二个任务的时候,第一个任务已经完成了,而且会复用执行第一个任务的线程,进而不用每次新建线程。
改变下,去掉睡眠,注释掉,输出结果
//Thread.sleep(i*1000);
当前线程:pool-1-thread-1输出:0
当前线程:pool-1-thread-3输出:2
当前线程:pool-1-thread-3输出:9
当前线程:pool-1-thread-5输出:4
当前线程:pool-1-thread-7输出:6
当前线程:pool-1-thread-2输出:1
当前线程:pool-1-thread-9输出:8
当前线程:pool-1-thread-6输出:5
当前线程:pool-1-thread-8输出:7
当前线程:pool-1-thread-4输出:3
去掉休眠,这种方式将会建立1-10个线程,获取cup时间片执行
而后,咱们一块儿来建立一个定长的线程池,这个线程池它支持定时及周期性的任务执行。延迟执行的示例代码如下图所示:表示延迟3秒执行代码。
当前线程:pool-1-thread-1输出:0
当前线程:pool-1-thread-1输出:2
当前线程:pool-1-thread-3输出:1
当前线程:pool-1-thread-3输出:4
当前线程:pool-1-thread-1输出:3
当前线程:pool-1-thread-2输出:5
当前线程:pool-1-thread-2输出:6
当前线程:pool-1-thread-2输出:7
当前线程:pool-1-thread-2输出:9
当前线程:pool-1-thread-4输出:8
以下图:表示延迟1秒后,每隔5秒执行一次代码即每隔5秒重复执行一次
当前线程:pool-1-thread-4输出:3
当前线程:pool-1-thread-1输出:0
当前线程:pool-1-thread-5输出:4
当前线程:pool-1-thread-2输出:1
当前线程:pool-1-thread-2输出:8
当前线程:pool-1-thread-2输出:9
当前线程:pool-1-thread-3输出:2
当前线程:pool-1-thread-5输出:7
当前线程:pool-1-thread-1输出:6
当前线程:pool-1-thread-4输出:5
当前线程:pool-1-thread-2输出:0
当前线程:pool-1-thread-1输出:3
当前线程:pool-1-thread-4输出:4
当前线程:pool-1-thread-5输出:2
当前线程:pool-1-thread-2输出:6
当前线程:pool-1-thread-2输出:8
当前线程:pool-1-thread-2输出:9
当前线程:pool-1-thread-3输出:1
当前线程:pool-1-thread-5输出:7
当前线程:pool-1-thread-4输出:5
而后,咱们一块儿来建立一个定长的线程池,能够控制线程的最大并发数,超出的任务会在队列中等待。示例代码以下图所示:
以上第三种方式建立线程池,由于线程池大小为4,每一个任务输出index后sleep 3秒,因此每3秒打印4个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()
最后,咱们一块儿来建立一个单线程化的线程池,单线程化的线程池,它只会用惟一的工做线程来执行任务,保证全部任务按照指定顺序(FIFO, LIFO, 优先级)来执行。示例代码如图:
当前线程:pool-1-thread-1输出:0
当前线程:pool-1-thread-1输出:1
当前线程:pool-1-thread-1输出:2
当前线程:pool-1-thread-1输出:3
当前线程:pool-1-thread-1输出:4
当前线程:pool-1-thread-1输出:5
当前线程:pool-1-thread-1输出:6
当前线程:pool-1-thread-1输出:7
当前线程:pool-1-thread-1输出:8
当前线程:pool-1-thread-1输出:9
代码的结果是依次输出的,就至关因而按顺序的执行了各个任务。
runState表示当前线程池的状态。
当线程池初始建立的时候,是running态。
当线程池处于shutdown态的时候,此线程池不可以接受新的任务,它会等待全部的任务执行完毕。
当线程池处于stop状态的时候,此线程不能接受新的任务,而且会去尝试终止正在执行的任务。
那线程池何时处于什么状态呢。当调用了shutdown()方法的时候就会处于shutdown状态,当调用了shutdownNow()方法的时候就会处于stop状态。
线程池中的线程是有数量限制的,根据任务类型来设置线程数量,若是是CPU密集型,则数量为NCPU+1,若是是IO密集型,则数量为2*NCPU,不少时候,为了安全性,仍是会设置上限,当新的任务来的时候,若是正常数量的线程都在用着,那么就用一个队列数据结构把新的任务缓存起来,如果新任务增加速度大于线程完成任务的速度,这时能够在线程数量尚未达到上限的时候建立新的线程来执行任务,但如果达到了上限并且任务缓存队列已经满了的话,则有必要采起拒绝措施,拒绝后续任务的到来。
这里有两个概念:
1)任务缓存队列(详细介绍在本博客其余篇幅有详细介绍,若有须要请参考)
常有这四种状况,咱们选用一个东西的时候确定是根据它的某些特征。
A、ArrayBlockingQueue:基于数组的先进先出队列,此队列建立时必须指定大小。
B、PriorityBlockingQueue:基于优先级的队列。
C、LinkedBlockingQueue:基于链表的先进先出队列,若是建立时没有指定大小,则默认为Integer.MAX_VALUE。
D、synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新的任务。
2)任务的拒绝措施:若是线程池中任务缓存队列已经满了而且线程池中线程数目达到maxmunPoolSize,若是还有任务来,就会采起任务拒绝策略,一般有一些四种策略。
A、ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
B、ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,可是不抛出异常。
C、ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,而后从新尝试执行任务(重复此过程)
D、ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
附录:返回ExecutorService接口
ExecutorService接口方法
ExecutorService实现类
顶层Executor接口的,最终在ThreadPoolExecutor里面有了具体的实现,这个方法就是用来让线程池执行某个任务的。