首先线程池有以下几个参数:
1.corePoolSize:表示线程池核心大小
2.maximumPoolSize:最大线程池大小
3.keepAliveTime和unit和在一起用于指定线程池中空闲线程的最大存活空间
4.workqueue:指工作队列
5.threadFactory:用于创建工作者线程的线程工厂
6.handler:线程池饱和时,封装被拒绝任务的处理策略
此外,线程池的执行过程是这样的:
1、每过来一个任务启动一个线程去执行
2、当核心线程数用完后,会把新来的线程任务存入阻塞队列中去
3、阻塞队列存满后,在启动超过核心线程数量到最大线程数量之间的线程
4、当线程的数量达到最大线程数量时,再来任务就会启动拒绝策略
接下来我们就来具体说一下线程池的拒绝策略:
线程池的拒绝策略有以下几种:
1.ThreadPoolExector.AbortPolicy
默认策略,丢弃任务并抛出RejectedException异常
我们能通过查看ThreadPoolExector的底层源码看到,能够创建一个默认策略,如下图:
举例说明:
public class L1 {
public static void main(String[] args) {
int corePoolSize=6;
int maximumPoolSize=10;
long keepAliveTime=6;
BlockingQueue<Runnable> workqueue=new LinkedBlockingQueue<Runnable>(10);
ThreadPoolExecutor executor=new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime,TimeUnit.MICROSECONDS, workqueue);
RejectedExecutionHandler handler=new ThreadPoolExecutor.AbortPolicy();
for(int i=0;i<50;i++) {
task myTask = new task(i);
executor.execute(myTask);
System.out.println("线程数目:" + executor.getPoolSize() + ",队列中等待执行的任务数目:" +
executor.getQueue().size() + ",已执行完的任务数目:" + executor.getCompletedTaskCount());
}
}
}
class task implements Runnable {
private int num;
public task(int num) {
this.num = num;
}
@Override
public void run() {
System.out.println("线程名称:" + Thread.currentThread().getName() + ",正在执行task " + num);
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task " + num + "执行完毕");
}
}
从图中能看到抛出了异常
2.ThreadPoolExector.DiscardPolicy
丢弃当前被拒绝的任务,且不抛出异常
public class L1 {
public static void main(String[] args) {
int corePoolSize=6;
int maximumPoolSize=10;
long keepAliveTime=6;
BlockingQueue<Runnable> workqueue=new LinkedBlockingQueue<Runnable>(10);
RejectedExecutionHandler handler=new ThreadPoolExecutor.DiscardPolicy();
ThreadPoolExecutor executor=new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MICROSECONDS, workqueue,handler);
for(int i=0;i<50;i++) {
task myTask = new task(i);
executor.execute(myTask);
System.out.println("线程数目:" + executor.getPoolSize() + ",队列中等待执行的任务数目:" +
executor.getQueue().size() + ",已执行完的任务数目:" + executor.getCompletedTaskCount());
}
}
}
class task implements Runnable {
private int num;
public task(int num) {
this.num = num;
}
@Override
public void run() {
System.out.println("线程名称:" + Thread.currentThread().getName() + ",正在执行task " + num);
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task " + num + "执行完毕");
}
}
从代码上跟默认策略一样,只是修改了这一句代码:
RejectedExecutionHandler handler=new ThreadPoolExecutor.DiscardPolicy();
运行之后也能看到并不像第一个拒绝策略一样报错,这个策略只是丢弃了任务但并不报错。
3.ThreadPoolExector.DiscardOldestPolicy
丢弃队列中的末尾任务(最旧的任务,也就是最早进入队列的任务)后,继续当前的任务提交给线程池
代码也只用修改一句,其他跟上面相同
RejectedExecutionHandler handler=new ThreadPoolExecutor.DiscardOldestPolicy();
从执行结果来看,这个拒绝策略丢弃队列中的末尾任务继续当前的任务
4.ThreadPoolExector.CallerRunsPolicy
交给调用线程池的线程进行处理(谁调用,谁处理)
代码改动:
RejectedExecutionHandler handler=new ThreadPoolExecutor.CallerRunsPolicy();
以上就是线程池的四种拒绝策略。