BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(10);//无界队列
// queue = new ArrayBlockingQueue<Runnable>(10); //有界队列
// queue = new SynchronousQueue<Runnable>(); //默认
ThreadPoolExecutor tpe = new ThreadPoolExecutor(5, 20, 1000, TimeUnit.MILLISECONDS, queue);
for(int i = 0;i<30;i++){ //创建30个线程,并提交任务
tpe.execute(new Runnable(){
public void run(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis());
}
});
}
tpe.shutdown(); //关闭线程池
出现RejectedExecutionException异常有两种原因:
1、当你设置的任务缓存队列过小的时候,或者说, 你的线程池里面所有的线程都在干活(线程数== maxPoolSize),并且你的任务缓存队列也已经充满了等待的队列, 这个时候,你再向它提交任务,则会抛出这个异常。
2、执行shutdown后再向线程池中添加任务
tpe.shutdown(); //关闭线程池
try{
tpe.execute(new Runnable(){
public void run(){
}
});
}catch(RejectedExecutionException e){
System.out.println("线程池关闭后不允许向线程池中添加任务");
}
此时会抛RejectedExecutionException异常。
饱和策略
当队列满时,此时便是饱和策略发挥作用的时候了,JDK中定义了四种饱和策略:
1、AbortPolicy:终止策略是默认的饱和策略,当队列满时,会抛出一个RejectExecutionException异常(第一段代码就是例子),客户可以捕获这个异常,根据需求编写自己的处理代码
2、DiscardPolicy:策略会悄悄抛弃该任务。
3、DiscardOldestPolicy:策略将会抛弃下一个将要执行的任务,如果此策略配合优先队列PriorityBlockingQueue,该策略将会抛弃优先级最高的任务
4、CallerRunsPolicy:调用者运行策略,该策略不会抛出异常,不会抛弃任务,而是将任务回退给调用者线程执行(调用execute方法的线程),由于任务需要执行一段时间,所以在此期间不能提交任务,从而使工作线程有时间执行正在执行的任务。
下面重点演示CallerRunsPolicy策略
@Test
public void testArrayBlokingQueue(){
//有界队列
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(10);
//调用者运行策略
ThreadPoolExecutor tpe = new ThreadPoolExecutor(5, 20, 1000, TimeUnit.MILLISECONDS, queue,new ThreadPoolExecutor.CallerRunsPolicy());
for(int i = 0;i<100;i++){
tpe.execute(new Runnable() {
@Override
public void run() {
//目的让更多任务让调用者线程执行
if(!Thread.currentThread().getName().equals("main")){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
//会输出很多调用者线程名
System.out.println(Thread.currentThread().getName());
}
});
}
tpe.shutdown();
}