Java线程池的工厂类:Executors类,数组
初始化4种类型的线程池:缓存
newCachedThreadPool()
说明:初始化一个能够缓存线程的线程池,默认缓存60s,线程池的线程数可达到Integer.MAX_VALUE,即2147483647,内部使用SynchronousQueue做为阻塞队列;
特色:在没有任务执行时,当线程的空闲时间超过keepAliveTime,会自动释放线程资源;当提交新任务时,若是没有空闲线程,则建立新线程执行任务,会致使必定的系统开销;
所以,使用时要注意控制并发的任务数,防止因建立大量的线程致使而下降性能。并发
newFixedThreadPool()
说明:初始化一个指定线程数的线程池,其中corePoolSize == maxiPoolSize,使用LinkedBlockingQuene做为阻塞队列
特色:即便当线程池没有可执行任务时,也不会释放线程。
newSingleThreadExecutor()
说明:初始化只有一个线程的线程池,内部使用LinkedBlockingQueue做为阻塞队列。
特色:保证全部任务按照指定顺序(FIFO, LIFO, 优先级)执行。若是该线程异常结束,会从新建立一个新的线程继续执行任务,惟一的线程能够保证所提交任务的顺序执行
newScheduledThreadPool()
特定:初始化的线程池能够在指定的时间内周期性的执行所提交的任务,在实际的业务场景中可使用该线程池按期的同步数据。框架
总结:除了newScheduledThreadPool的内部实现特殊一点以外,其它线程池内部都是基于ThreadPoolExecutor类(Executor的子类)实现的。ide
public class MyRunnable implements Runnable { private Integer index; public MyRunnable(Integer index) { this.index = index; } @Override public void run() { System.out.println(index); } public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { executorService.execute(new MyRunnable(i)); } executorService.shutdown(); } }
结果:性能
public class MyRunnable implements Runnable { private Integer index; public MyRunnable(Integer index) { this.index = index; } @Override public void run() { System.out.println(index); } public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { executorService.execute(new MyRunnable(i)); } executorService.shutdown(); } }
结果:优化
建立一个定长的线程池,并且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。this
延迟3秒执行,延迟执行示例代码以下:spa
public class MyThreadPool { public static void main(String[] args) { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.schedule(new Runnable() { @Override public void run() { System.out.println("delay 3 seconds"); } }, 3, TimeUnit.SECONDS); scheduledThreadPool.shutdown(); } }
表示延迟1秒后每3秒执行一次,按期执行示例代码以下:线程
public class MyThreadPool { public static void main(String[] args) { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("delay 1 seconds, and excute every 3 seconds"); } }, 1, 3, TimeUnit.SECONDS); try { Thread.sleep(10000); scheduledThreadPool.shutdown(); } catch (InterruptedException e) { e.printStackTrace(); } } }
调用shutdown就会结束线程池退休循环
ThreadPoolExecutor类构造器语法形式:
ThreadPoolExecutor(corePoolSize,maxPoolSize,keepAliveTime,timeUnit,workQueue,threadFactory,handle);
方法参数:
corePoolSize:核心线程数
maxPoolSize:最大线程数
keepAliveTime:线程存活时间(在corePore<*<maxPoolSize状况下有用)
timeUnit:存活时间的时间单位
workQueue:阻塞队列(用来保存等待被执行的任务)
注:关于workQueue参数的取值,JDK提供了4种阻塞队列类型供选择:
ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;
LinkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任务,吞吐量一般要高于
SynchronousQuene:一个不存储元素的阻塞队列,每一个插入操做必须等到另外一个线程调用移除操做,不然插入操做一直处于阻塞状态,吞吐量一般要高于ArrayBlockingQuene;
PriorityBlockingQuene:具备优先级的无界阻塞队列;
threadFactory:线程工厂,主要用来建立线程;
handler:表示当拒绝处理任务时的策略,有如下四种取值
注: 当线程池的饱和策略,当阻塞队列满了,且没有空闲的工做线程,若是继续提交任务,必须采起一种策略处理该任务,线程池提供了4种策略:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,可是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,而后从新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
固然也能够根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。
其中AtomicInteger变量ctl的功能很是强大:利用低29位表示线程池中线程数,经过高3位表示线程池的运行状态:
一、RUNNING:-1 << COUNT_BITS,即高3位为111,该状态的线程池会接收新任务,并处理阻塞队列中的任务;
二、SHUTDOWN: 0 << COUNT_BITS,即高3位为000,该状态的线程池不会接收新任务,但会处理阻塞队列中的任务;
三、STOP : 1 << COUNT_BITS,即高3位为001,该状态的线程不会接收新任务,也不会处理阻塞队列中的任务,并且会中断正在运行的任务;
四、TIDYING : 2 << COUNT_BITS,即高3位为010,该状态表示线程池对线程进行整理优化;
五、TERMINATED: 3 << COUNT_BITS,即高3位为011,该状态表示线程池中止工做;
有两种方式:
Executor.execute(Runnable command);
ExecutorService.submit(Callable<T> task);
1.首次经过workCountof()获知当前线程池中的线程数,
若是小于corePoolSize, 就经过addWorker()建立线程并执行该任务;
不然,将该任务放入阻塞队列;
2. 若是能成功将任务放入阻塞队列中,
若是当前线程池是非RUNNING状态,则将该任务从阻塞队列中移除,而后执行reject()处理该任务;
若是当前线程池处于RUNNING状态,则须要再次检查线程池(由于可能在上次检查后,有线程资源被释放),是否有空闲的线程;若是有则执行该任务;
三、若是不能将任务放入阻塞队列中,说明阻塞队列已满;那么将经过addWoker()尝试建立一个新的线程去执行这个任务;若是addWoker()执行失败,说明线程池中线程数达到maxPoolSize,则执行reject()处理任务;
会将提交的Callable任务会被封装成了一个FutureTask对象
FutureTask类实现了Runnable接口,这样就能够经过Executor.execute()提交FutureTask到线程池中等待被执行,最终执行的是FutureTask的run方法;
比较:
两个方法均可以向线程池提交任务,execute()方法的返回类型是void,它定义在Executor接口中, 而submit()方法能够返回持有计算结果的Future对象,它定义在ExecutorService接口中,它扩展了Executor接口,其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。
线程池的关闭(2种)
ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown()和shutdownNow(),其中:
shutdown():不会当即终止线程池,而是要等全部任务缓存队列中的任务都执行完后才终止,但不再会接受新的任务
shutdownNow():当即终止线程池,并尝试打断正在执行的任务,而且清空任务缓存队列,返回还没有执行的任务
ThreadPoolExecutor提供了动态调整线程池容量大小的方法:setCorePoolSize()和setMaximumPoolSize(),