线程池(Thread Pool)是一种基于池化思想管理线程的工具,常常出如今多线程服务器中,如MySQL。java
咱们都知道线程的建立和销毁都须要必定的资源开销,下降了计算机的总体性能。那么有没有一种办法能避免频繁的线程建立和销毁呢?基于此就引出了线程池的概念,使用线程池能够带来一系列好处:缓存
Java中JDK8的线程池核心实现类是ThreadPoolExecutor,咱们首先来看一下ThreadPoolExecutor的UML类图,了解下ThreadPoolExecutor的继承关系。服务器
ThreadPoolExecutor实现的顶层接口是Executor,顶层接口Executor提供了一种思想:将任务提交和任务执行进行解耦。用户无需关注如何建立线程,如何调度线程来执行任务,用户只需提供Runnable对象,将任务的运行逻辑提交到执行器(Executor)中,由Executor框架完成线程的调配和任务的执行部分。ExecutorService接口增长了一些能力:(1)扩充执行任务的能力,补充能够为一个或一批异步任务生成Future的方法;(2)提供了管控线程池的方法,好比中止线程池的运行。AbstractExecutorService则是上层的抽象类,将执行任务的流程串联了起来,保证下层的实现只需关注一个执行任务的方法便可。最下层的实现类ThreadPoolExecutor实现最复杂的运行部分,ThreadPoolExecutor将会一方面维护自身的生命周期,另外一方面同时管理线程和任务,使二者良好的结合从而执行并行任务。markdown
一、newCachedThreadPool建立一个可缓存线程池,若是线程池长度超过处理须要,可灵活回收线程,若无可回收,则新建线程;线程池无限大,当执行第二个任务时第一个任务已完成,会复用执行第一个任务的线程,而不是新建线程。多线程
二、newFixedThreadPool建立一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待;初始线程数和最大线程数同样,若是要执行的线程大于初始线程数,则会将多余的线程任务加入到缓存队列中等待执行。并发
三、newScheduledThreadPool建立一个定长线程池,支持定时及周期性任务的执行;框架
四、newSingleThreadExecutor建立一个单线程化的线程池,它只会用惟一的工做线程来执行任务,保证全部任务按照指定顺序(FIFO,LIFO,优先级)执行;异步
public class ThreadPoolDemo {
public static void main(String[] args)throws Exception {
ExecutorService threadPool = Executors.newCachedThreadPool();
}
}
复制代码
咱们点进newCachedThreadPool()方法会看到以下内容:高并发
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
//咱们发现第二个参数为Integer.MAX_VALUE,也就是最大的工做线程数为Integer.MAX_VALUE,若是超高并发过来会直接OOM。
复制代码
因此咱们得经过new ThreadPoolExecutor()来本身指定参数。工具
构造方法以下:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 复制代码
流程图以下:
当任务过来时,首先会先去判断线程池中工做的线程数量是否到达核心线程数,若是没达到就直接执行,若是达到了就查看工做队列是否满。若是没满就将任务放入到工做队列中,若是满了就增长工做线程数来处理任务。若是工做线程和队列都满了的话就会用制定的策略去拒绝任务。
AbortPolicy(默认):直接抛出异常RejectedExecutionException异常阻止系统正常运行。
CallerRunsPolicy:调用者运行是一种调节机制,该策略既不会抛弃任务,也不会抛弃异常,而是将某些任务回退到调用者,从而下降新任务的流量。
DiscardOldestPolicy:丢弃队列中等待最久的任务,而后把当前任务加入队列中尝试再次提交当前任务。
DiscardPolicy:直接丢弃任务,不予处理也不抛出异常。若是容许任务丢失,这是最好的一种方案。
代码演示拒绝策略:
1.AbortPolicy
public static void main(String[] args)throws Exception {
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
try {
for (int i = 0; i < 10; i++) {
poolExecutor.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t办理业务");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
poolExecutor.shutdown();
}
System.out.println(Thread.currentThread().getName()+"\t办理业务");
}
复制代码
也就是说明当工做线程和工做队列都满了以后线程池会拒绝任务直接报错。
2.CallerRunsPolicy
public static void main(String[] args)throws Exception {
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
try {
for (int i = 0; i < 10; i++) {
poolExecutor.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t办理业务");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
poolExecutor.shutdown();
}
System.out.println(Thread.currentThread().getName()+"\t办理业务");
}
复制代码
也就是说明当工做线程和工做队列都满了以后会将任务返还给调用线程池的人,让他去处理。
3.DiscardOldestPolicy和DiscardPolicy
public static void main(String[] args)throws Exception {
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy());
try {
for (int i = 0; i < 10; i++) {
poolExecutor.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t办理业务");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
poolExecutor.shutdown();
}
System.out.println(Thread.currentThread().getName()+"\t办理业务");
}
复制代码
一共输出了10条记录,说明有一条消息被抛弃了。