1. 四种线程池创建方式,底层都是依赖ThreadPoolExecutor这个方法
ExecutorService executorService=Executors.newFixedThreadPool(10);
ExecutorService executorService1=Executors.newCachedThreadPool();
ExecutorService executorService2=Executors.newScheduledThreadPool(10);
ExecutorService executorService3=Executors.newSingleThreadExecutor();
2. ThreadPoolExecutor的重要参数
public ThreadPoolExecutor(int corePoolSize,//核心线程数
int maximumPoolSize,//最大线程数
long keepAliveTime,//线程执行和存活时间
TimeUnit unit,//线程执行和存活时间单位
BlockingQueue<Runnable> workQueue,//任务队列
RejectedExecutionHandler handler//队列满了,执行的拒绝策略) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
3. ThreadPoolExecutor的执行策略
在使用有界队列时,若有新的任务需要执行,如果线程池实际线程数小于corePoolSize,则优先创建线程,若大于corePoolSize,则会将任务加入队列,若队列已满,则在总线程数不大于maximumPoolSize的前提下,创建新的线程,若线程数大于maximumPoolSize,则执行拒绝策略。或其他自定义方式(拒绝方式一般选择是记入日志,任务id,关键key,非高峰期重新批处理)。
若使用无界队列,则不存在任务进入队列失败的情况.这种情况下线程数达到corePoolSize就不会继续创建新线程,后续任务一直进入堆积,直到系统资源耗尽.
下面是一个demo
Main代码
public class UseThreadPoolExecutor1 {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(
1, //coreSize
2, //MaxSize
60, //60
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(3) //指定一种队列 (有界队列)
//new LinkedBlockingQueue<Runnable>()
, new MyRejected()
//, new DiscardOldestPolicy()
);
MyTask mt1 = new MyTask(1, "任务1");
MyTask mt2 = new MyTask(2, "任务2");
MyTask mt3 = new MyTask(3, "任务3");
MyTask mt4 = new MyTask(4, "任务4");
MyTask mt5 = new MyTask(5, "任务5");
MyTask mt6 = new MyTask(6, "任务6");
pool.execute(mt1);
//pool.execute(mt2);
//pool.execute(mt3);
//pool.execute(mt4);
//pool.execute(mt5);
//pool.execute(mt6);
pool.shutdown();
}
}
Task代码
public class MyTask implements Runnable {
private int taskId;
private String taskName;
public MyTask(int taskId, String taskName){
this.taskId = taskId;
this.taskName = taskName;
}
public int getTaskId() {
return taskId;
}
public void setTaskId(int taskId) {
this.taskId = taskId;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
try {
System.out.println("run taskId =" + this.taskId+" Thread"+Thread.currentThread().getId());
Thread.sleep(5*1000);
//System.out.println("end taskId =" + this.taskId);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String toString(){
return Integer.toString(this.taskId);
}
}
MyRejected代码
public class MyRejected implements RejectedExecutionHandler{
public MyRejected(){
}
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("自定义处理..");
System.out.println("当前被拒绝任务为:" + r.toString());
}
}
1.只保留1个 pool.execute方法 log信息如下
run taskId =1 Thread11
2.保留2个 pool.execute方法 log信息如下
run taskId =1 Thread11
run taskId =2 Thread11
//只有一个线程操作,中间有间隔时间等待task1完成.
3.保留5个 pool.execute方法 log信息如下
//第一时间1和5同时执行
run taskId =1 Thread11
run taskId =5 Thread12
//过一会2,3,4顺序执行
run taskId =2 Thread11
run taskId =3 Thread12
run taskId =4 Thread11
//执行顺序解读
1.task1,2,3,4,5陆续添加到线程池中之行
2.线程中有一个核心线程,task1立即执行
3.task1执行过程中,2,3,4被放入队列中,但是由于队列容量只有3(ArrayBlockingQueue<Runnable>(3)),task5进入不了队列
4.线程池判断核心线程数<最大线程数,又新开了一个线程,立刻执行线程5
5.task1,5执行完成之后,ThreadPool存在2条线程依次执行任务2,3,4
4.保留6个 pool.execute方法 log信息如下
自定义处理..
run taskId =5 Thread12
当前被拒绝任务为:6
run taskId =1 Thread11
run taskId =2 Thread11
run taskId =3 Thread12
run taskId =4 Thread11
//当执行线程池和队列都满了以后直接执行拒绝策略
5.保留6个 pool.execute方法 将构造方法中的队列替换成‘new LinkedBlockingQueue<Runnable>() ’ log信息如下
run taskId =1 Thread11
run taskId =2 Thread11
run taskId =3 Thread11
run taskId =4 Thread11
run taskId =5 Thread11
run taskId =6 Thread11
//当队列换成了无界队列后,只初始化了一个线程,只有一个线程执行任务,maxsize这个参数失效