线程池
线程池
线程池是一种线程容器,在线程池中,有一些活跃线程,当需要线程的时候可以从线程池中获取一个线程,当完成工作后,可以将线程放回到线程池中,方便其他人使用。线程池避免了每次需要线程的时候都要创建线程和销毁线程,节省了时间和空间开销,提升了性能。
JDK内置支持线程池,在concurrent并发包里包含了线程池的相关类。Executors类是线程池工厂,通过Executors可以获得特定功能的线程池。
Executors的主要工厂方法如下:
public static ExecutorService newFixedThreadPool (int nThread);
public static ExecutorService newSingleThreadExecutor ();
public static ExecutorService newCachedThreadPool ();
public static ScheduledExecutorService newSingleThreadSchuduledExecutor ();
public static ScheduledExecutorService newScheduledThreadPool (int corePoolSize);
这些方法会返回特定功能的线程池:
•newFixedThreadPool()方法,返回一个固定线程数量的线程池。该线程池中的数量始终不变。当有一个新的任务提交时,线程池中如果有空闲的线程,则立即执行。若没有,则新的任务会被放在一个任务队列中,待有线程空闲时,便处理任务队列中的任务。
•newSingleThreadExecutor()方法,返回一个只有一个线程的线程池。若多于一个任务被提交到该线程池,则任务被保存在一个任务队列中,待线程空闲,按先进先出的顺序执行队列中的任务。
•newCachedThreadPool()方法,返回一个可根据实际情况调整线程数量的线程池。线程池中线程的数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程都在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务完成之后,进入线程池进行复用。
•newSingleThreadSchuduledExecutor()方法,返回一个ScheduledExecutorService对象,线程池大小为1。ScheduledExecutorService在ExecutorService接口基础上扩展了功能,可以在给定时间执行某个任务,如在固定的时间后执行或者周期性的执行某个任务。
•newScheduledThreadPool(int corePoolSize)方法,也返回一个ScheduledExecutorService对象,但是线程池可以指定线程数量。
应用示例:
public class ThreadPoolDemo implements Runnable{
public void run(){
System.out.println("I am "+Thread.currentThread().getName());
}
public static void main(String[] args) {
ThreadPoolDemo demo=new ThreadPoolDemo ();
ExecutorService exe=Executors.newFixedThreadPool (3);
// ExecutorService exe=Executors.newSingleThreadExecutor ();
// ExecutorService exe=Executors.newCachedThreadPool ();
for(int i=0; i<6; i++){
exe.execute (demo);
// exe.submit (demo);//与上一句有些许差别
}
}
}
1、核心线程池的内部实现
对于几个核心的线程池,newFixedThreadPool()、newSingleThreadExecutor()和newCachedThreadPool(),它们的内部实现都使用了ThreadPoolExecutor。
三个线程池的实现方式:
从上述代码可以看出,这三个核心线程池都是ThreadPoolExecutor类的封装。下面看一下ThreadPoolExecutor的构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
构造函数的各个参数含义如下:
corePoolSize:指定了线程池中线程的数量。
maximumPoolSize:指定了线程池中线程的最大数量。
keepAliveTime:当线程池中线程数量超过corePoolSize时,多余的空闲线程的存活时间。即,超过corePoolSize的线程,在多长时间后会被销毁。
unit:keepAliveTime的时间单位。
workQueue:任务队列,存放被提交但尚未被执行的任务。
threadFactory:线程工厂,用于创建线程,一般使用默认。
handler:拒绝策略,当任务太多来不及处理,如何拒绝任务。
workQueue参数:
其是一个BlockingQueue接口的对象,仅用于存放Runnable对象。ThreadPoolExecutor的构造函数中可以使用如下几种BlockingQueue:
•直接提交的队列:SynchronousQueue。SynchronousQueue没有容量,每一个插入操作都要等待一个相应的删除操作,每一个删除操作都要等待对应的插入操作。使用Synchronous,并不会真正保存任务,其总是将新任务提交给线程执行,如果没有空闲的线程,则新建一个线程,如果线程数量已经达到最大值,则执行拒绝策略。
•有界任务队列:ArrayBlockingQueue,需要指定该队列的最大容量。若使用有界的任务队列,当有新的任务需要执行,如果线程池的实际线程个数小于corePoolSize,则会优先创建线程,若大于corePoolSize,则会将新任务添加到任务等待队列。若队列已满,无法加入,若总线程数小于maximumPoolSize,则创建新线程执行任务。若大于maximumPoolSize,则执行拒绝策略。
•*任务队列:LinkedBlockingQueue。与有界任务队列相比,除非系统资源耗尽,否则*任务队列不存在入队失败。若使用*任务队列,当有新的任务到来,如果线程数量小于corePoolSize,则创建新的线程执行任务,当线程数达到corePoolSize时,就不会再增加。若后续还有新任务,直接加入到队列中。
•优先任务队列:PriorityBlockingQueue,其是带有执行优先级的队列,是一个特殊的*队列。ArrayBlockingQueue和LinkedBlockingQueue都是按照先进先出处理任务的。而PriorityBlockingQueue是根据任务自身的优先级选择任务执行。
ThreadPoolExecutor调度策略:
handler:拒绝策略
拒绝策略是系统超负荷运行时的补救措施,通常是由于压力太大而引起的,也就是线程池中的线程已经用完了,无法继续为新任务服务,同时,等待队列中也已经排满了,再也塞不下新任务。这时就需要拒绝策略处理这个问题。
JDK内置四种拒绝策略:
•AbortPolicy策略:该策略会直接抛出异常,阻止系统正常工作。
•CallerRunsPolicy策略:只要线程池未关闭,该策略直接在调用者线程中运行任务,不会真正丢弃任务,但会导致提交任务的线程性能急剧下降。
•DiscardOldestPolicy策略:丢弃一个最老的请求,并尝试再次提交该任务。
•DiscardPolicy策略:默默丢弃无法处理的任务,不作任何处理。
参考:《实战Java高并发程序设计》
上一篇: Spring boot 整合 cas Java client
下一篇: 线程池