java 线程池ThreadPoolExecutor
一、线程池的作用
1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
二、线程池ThreadPoolExecutor
1.接口说明
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
各个参数的含义:
corePoolSize:线程池维护线程的最少线程数,也是核心线程数,包括空闲线程。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
maximumPoolSize: 线程池维护线程的最大线程数,它表示在线程池中最多能创建多少个线程;
keepAliveTime: 线程池维护线程所允许的空闲时间.表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。
unit: 线程池维护线程所允许的空闲时间的单位,keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
workQueue:用于保存等待执行的任务的阻塞队列,阻塞队列有以下几种选择:
ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。
SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于 LinkedBlockingQueue
threadFactory:线程工厂,主要用来创建线程;
handler: 线程池对拒绝任务的处理策略 有以下四种取值:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
2.工作原理:
任务通过execute(Runnable)方法添加到线程池,一个任务就是一个Runnable对象,任务的执行就是Runnable对象的run()方法.
当一个任务将被添加到线程池中时:
如果当前线程数小于corePoolSize,即使有空闲线程,也会创建新的线程来处理新增任务;
如果当前线程数等于corePoolSize,如果缓冲队列未满,该任务被放入缓冲队列,池子里的空闲线程就去从workQueue中取任务并处理
如果当前线程数大于corePoolSize,且冲队列已满,如果当前线程数小于maximumPoolSize, 就创建新的线程来处理新增任务;
如果当前线程数等于maximumPoolSize,且冲队列已满,将会使用handler所指定的策略来处理任务.
线程池处理任务的顺序是:
核心线程corePoolSize, 缓冲队列workQueue, 最大线程maximumPoolSize
当前线程数大于corePoolSize,线程池中的空闲线程在超过keepAliveTime, 会自动终止.线程池通过keepAliveTime来动态维护线程数.
3.代码
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class TestThreadPool {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 20, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(2),
new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "T" + this.threadIndex.incrementAndGet());
}
},
new ThreadPoolExecutor.DiscardOldestPolicy());
for(int i=0;i<9;i++){
MyTask myTask = new MyTask(i);
System.out.println("创建任务并提交到线程池中:任务" + i);
executor.execute(myTask);
System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount());
}
executor.shutdown();
}
}
class MyTask implements Runnable {
private int taskNum;
public MyTask(int num) {
this.taskNum = num;
}
@Override
public void run() {
System.out.println("正在执行task "+taskNum+";Thread.currentThread().getName()="+Thread.currentThread().getName());
try {
Thread.currentThread().sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task "+taskNum+"执行完毕"+";Thread.currentThread().getName()="+Thread.currentThread().getName());
}
}
运行结果
创建任务并提交到线程池中:任务0
正在执行task 0;Thread.currentThread().getName()=T1
线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务1
线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务2
正在执行task 1;Thread.currentThread().getName()=T2
线程池中线程数目:2,队列中等待执行的任务数目:1,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务3
线程池中线程数目:2,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务4
线程池中线程数目:3,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务5
正在执行task 4;Thread.currentThread().getName()=T3
线程池中线程数目:4,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
正在执行task 5;Thread.currentThread().getName()=T4
创建任务并提交到线程池中:任务6
线程池中线程数目:4,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务7
线程池中线程数目:4,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
创建任务并提交到线程池中:任务8
线程池中线程数目:4,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
task 0执行完毕;Thread.currentThread().getName()=T1
task 1执行完毕;Thread.currentThread().getName()=T2
正在执行task 7;Thread.currentThread().getName()=T1
正在执行task 8;Thread.currentThread().getName()=T2
task 5执行完毕;Thread.currentThread().getName()=T4
task 4执行完毕;Thread.currentThread().getName()=T3
task 7执行完毕;Thread.currentThread().getName()=T1
task 8执行完毕;Thread.currentThread().getName()=T2
对结果分析
程序中一共有四个线程,分别是T1、T2、T3、T4.
任务:task2、task3、task6被丢弃了