频道栏目
首页 > 资讯 > Java > 正文

Java并发编程实战教程之线程池的饱和策略

18-06-28        来源:[db:作者]  
收藏   我要投稿

通常情况下,线程池会判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。但是如果有限队列已经满了,则会交给饱和策略来处理这个任务。

ThreadPoolExecutor 的饱和策略可以通过调用 setRejectedExecutionHandler 来修改。JDK 提供了下面几种不同的饱和策略。

AbortPolicy CallerRunsPolicy DiscardPolicy DiscardOldestPolicy

下面我们举例来逐个来说明,先看下面代码,我们创建一个线程池,然后创建一个函数 getPolicy() 用于获取不同的饱和策略。通过传入不同的饱和策略参数变量选择不同的策略,通过执行结果来检查饱和策略的效果。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolRejectedPolicyTest{

 //线程池大小
 private static final int THREAD_SIZE = 2;
 //任务数量
 private static final int TASK_SIZE = 5;
 //饱和策略
 private static final int ABORT_POLICY = 0;//Abort 策略
 private static final int CALLER_RUNS_POLICY = 1;//CallerRuns 策略
 private static final int DISCARD_POLICY = 2;//Discard策略
 private static final int DISCARD_OLDEST_POLICY = 3;//DiscardOlds策略

 //策略选择变量,改这个值选择不同的饱和策略
 private static int selectedPolicy = ABORT_POLICY;

 @SuppressWarnings("unchecked")
 public static void main(String[] args) {
  //阻塞队列只能容纳一个任务
  BlockingQueue Q = new LinkedBlockingDeque<>(1);
  //创建一个固定线程的线程池
  ThreadPoolExecutor service = new ThreadPoolExecutor(THREAD_SIZE,THREAD_SIZE,0L, TimeUnit.MILLISECONDS,Q);
  //设置线程池的饱和策略
  service.setRejectedExecutionHandler(getPolicy(selectedPolicy));
  //提交任务
  for(int i = 0; i < TASK_SIZE; i++) {
service.submit(new Task(i));
  }
  service.shutdown();
 }

 //任务
 static class Task implements Runnable {
  //任务ID
  private int taskId;
  public Task(int id) {
taskId = id;
  }

  @Override
  public void run() {
try {
 Thread.sleep(50);
} catch (InterruptedException e) {
 System.err.println("线程被中断" + e.getMessage());  
}
//打印当前任务信息
System.out.println("Task " + taskId + " is running on " + Thread.currentThread().getName());
  }
 }

 //饱和策略
 static RejectedExecutionHandler getPolicy(int policy) {
  switch (policy) {
  case ABORT_POLICY:
return new ThreadPoolExecutor.AbortPolicy();
  case CALLER_RUNS_POLICY:
return new ThreadPoolExecutor.CallerRunsPolicy();
  case DISCARD_POLICY:
return new ThreadPoolExecutor.DiscardPolicy();
  case DISCARD_OLDEST_POLICY:
return new ThreadPoolExecutor.DiscardOldestPolicy();
  default:
break;
  }

  return new ThreadPoolExecutor.AbortPolicy();
 }
}

AbortPolicy

将上面代码的变量 selectedPolicy 设置为 ABORT_POLICY。

selectedPolicy = ABORT_POLICY

运行程序,执行结果如下:

如上所示,执行了三个任务,第四个提交的时候,直接抛出异常,并且JVM一直处于运行状态。任务0和任务1已提交就被线程池中的两个线程执行,任务2提交到阻塞队列等待执行,这个时候继续提交任务,由于队列已满,触发饱和策略,直接抛出异常。

CallerRunsPolicy

将上面代码的变量 selectedPolicy 设置为 CALLER_RUNS_POLICY。

selectedPolicy = CALLER_RUNS_POLICY

运行程序,执行结果如下:

如上所示,所有任务都被执行,不会被抛弃也不会有异常抛出。任务0,1,2都在线程池中的线程执行。任务3,4则是由main线程执行。这说明,CallerRunsPolicy 饱和策略在队列已满的情况下,会把后面提交的任务给回调用者线程去执行。换句话说就是在调用exector的线程中运行新的任务。

DiscardPolicy

将上面代码的变量 selectedPolicy 设置为 DISCARD_POLICY。

selectedPolicy = DISCARD_POLICY

运行程序,执行结果如下:

如上所示,只执行了任务0,1,3。其他任务直接被抛弃。所以 DiscardPolicy 正如其名字,简单粗暴,队列满后新任务通通都抛弃。

DiscardOldestPolicy

将上面代码的变量 selectedPolicy 设置为 DISCARD_OLDEST_POLICY。

selectedPolicy = DISCARD_OLDEST_POLICY

运行程序,执行结果如下:

如上所示,只执行了任务0,1,4。其他任务2,3直接被抛弃。所以 DiscardOldestPolicy 也可以说正如其名字,简单粗暴,队列满后等待最久的任务将被新任务替换。

以上就是 JDK 提供的四个饱和策略,本文到此完结。

相关TAG标签
上一篇:js+jstl+servlet实现文件上传、列表展示及文件下载的代码详解
下一篇:C#判断语句、C#循环实例讲解
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站