源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

java线程池工作队列饱和策略代码示例

  • 时间:2022-11-26 01:43 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:java线程池工作队列饱和策略代码示例
线程池(Thread Pool) 是并行执行任务收集的实用工具。随着 CPU 引入适合于应用程序并行化的多核体系结构,线程池的作用正日益显现。通过 ThreadPoolExecutor类及其他辅助类,Java 5 引入了这一框架,作为新的并发支持部分。 ThreadPoolExecutor框架灵活且功能强大,它支持特定于用户的配置并提供了相关的挂钩(hook)和饱和策略来处理满队列 Java线程池会将提交的任务先置于工作队列中,在从工作队列中获取(SynchronousQueue直接由生产者提交给工作线程)。那么工作队列就有两种实现策略:无界队列和有界队列。无界队列不存在饱和的问题,但是其问题是当请求持续高负载的话,任务会无脑的加入工作队列,那么很可能导致内存等资源溢出或者耗尽。而有界队列不会带来高负载导致的内存耗尽的问题,但是有引发工作队列已满情况下,新提交的任务如何管理的难题,这就是线程池工作队列饱和策略要解决的问题。 饱和策略分为:Abort 策略, CallerRuns 策略,Discard策略,DiscardOlds策略。 为了更好的理解,我编写一个小的例子。
package concurrency.pool;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class SaturationPolicy {
 /**
   * 线程池工作队列已满时,在不同饱和策略下表现
   * @param handler 线程池工作队列饱和策略
   */
 public static void policy(RejectedExecutionHandler handler){
  //基本线程2个,最大线程数为3,工作队列容量为5
  ThreadPoolExecutor exec = new ThreadPoolExecutor(2,3,0l, TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>(5));
  if (handler != null){
   exec.setRejectedExecutionHandler(handler);
   //设置饱和策略
  }
  for (int i = 0; i < 10; i++) {
   exec.submit(new Task());
   //提交任务
  }
  exec.shutdown();
 }
 public static void main(String[] args) {
  //    policy(new ThreadPoolExecutor.AbortPolicy());
  //    policy((new ThreadPoolExecutor.CallerRunsPolicy()));
  //    policy(new ThreadPoolExecutor.DiscardPolicy());
  //    policy(new ThreadPoolExecutor.DiscardOldestPolicy());
 }
 //自定义任务
 static class Task implements Runnable {
  private static int count = 0;
  private int id = 0;
  //任务标识
  public Task() {
   id = ++count;
  }
  @Override
      public void run() {
   try {
    TimeUnit.SECONDS.sleep(3);
    //休眠3秒
   }
   catch (InterruptedException e) {
    System.err.println("线程被中断" + e.getMessage());
   }
   System.out.println(" 任务:" + id + "\t 工作线程: "+ Thread.currentThread().getName() + " 执行完毕");
  }
 }
}
当工作队列满了,不同策略的处理方式为: 1.Abort策略:默认策略,新任务提交时直接抛出未检查的异常RejectedExecutionException,该异常可由调用者捕获。 在主函数中添加如下代码:
policy(new ThreadPoolExecutor.AbortPolicy()); 
运行结果为: [img]http://files.jb51.net/file_images/article/201711/20171123105023483.png?20171023105036[/img] 程序抛出了RejectedExecutionException,并且一共运行了8个任务(线程池开始能运行3个任务,工作队列中存储5个队列)。当工作队列满了的时候,直接抛出了异常,而且JVM一直不退出(我现在也不知道什么原因)。我们可以看到执行任务的线程全是线程池中的线程。 2.CallerRuns策略:为调节机制,既不抛弃任务也不抛出异常,而是将某些任务回退到调用者。不会在线程池的线程中执行新的任务,而是在调用exector的线程中运行新的任务。 在主函数运行:
policy((new ThreadPoolExecutor.CallerRunsPolicy())); 
运行结果 [img]http://files.jb51.net/file_images/article/201711/20171123105214872.png?20171023105226[/img] 所有的任务都被运行,且有2(10 - 3 -5)个任务是在main线程中执行成功的,8个任务在线程池中的线程执行的。 3.Discard策略:新提交的任务被抛弃。 在main函数中运行
policy(new ThreadPoolExecutor.DiscardPolicy()); 
[img]http://files.jb51.net/file_images/article/201711/20171123105413583.png?20171023105424[/img] 通过上面的结果可以显示:没有异常抛出,后面提交的2个新任务被抛弃,只处理了前8(3+5)个任务,JVM退出。 4.DiscardOldest策略:队列的是“队头”的任务,然后尝试提交新的任务。(不适合工作队列为优先队列场景) 在main函数中运行如下方法
policy(new ThreadPoolExecutor.DiscardOldestPolicy()); 
运行结果:一共运行8个任务,程序结束,后面添加的任务9,任务10被执行了,而前面的任务3,任务4被丢弃。 [img]http://files.jb51.net/file_images/article/201711/20171123105546121.png?20171023105558[/img] [b]总结[/b] 以上就是本文关于java线程池工作队列饱和策略代码示例的全部内容,希望对大家有所帮助。如有不足之处,欢迎留言指出。感谢朋友们对本站的支持。
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部