Java concurrency线程池之线程池原理(四)_动力节点Java学院整理

 更新时间:2017年06月15日 15:03:33   作者:skywang12345  
这篇文章主要为大家详细介绍了Java concurrency线程池之线程池原理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

拒绝策略介绍

线程池的拒绝策略,是指当任务添加到线程池中被拒绝,而采取的处理措施。

当任务添加到线程池中之所以被拒绝,可能是由于:第一,线程池异常关闭。第二,任务数量超过线程池的最大限制。

线程池共包括4种拒绝策略,它们分别是:AbortPolicy, CallerRunsPolicy, DiscardOldestPolicy和DiscardPolicy。

  1. AbortPolicy         -- 当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常。
  2. CallerRunsPolicy    -- 当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。
  3. DiscardOldestPolicy -- 当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。
  4. DiscardPolicy       -- 当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。

线程池默认的处理策略是AbortPolicy!

拒绝策略对比和示例

下面通过示例,分别演示线程池的4种拒绝策略。

1. DiscardPolicy 示例

 import java.lang.reflect.Field;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.ThreadPoolExecutor.DiscardPolicy;
 
 public class DiscardPolicyDemo {
 
   private static final int THREADS_SIZE = 1;
   private static final int CAPACITY = 1;
 
   public static void main(String[] args) throws Exception {
 
     // 创建线程池。线程池的"最大池大小"和"核心池大小"都为1(THREADS_SIZE),"线程池"的阻塞队列容量为1(CAPACITY)。
     ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS,
         new ArrayBlockingQueue<Runnable>(CAPACITY));
     // 设置线程池的拒绝策略为"丢弃"
     pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
 
     // 新建10个任务,并将它们添加到线程池中。
     for (int i = 0; i < 10; i++) {
       Runnable myrun = new MyRunnable("task-"+i);
       pool.execute(myrun);
     }
     // 关闭线程池
     pool.shutdown();
   }
 }
 
 class MyRunnable implements Runnable {
   private String name;
   public MyRunnable(String name) {
     this.name = name;
   }
   @Override
   public void run() {
     try {
       System.out.println(this.name + " is running.");
       Thread.sleep(100);
     } catch (Exception e) {
       e.printStackTrace();
     }
   }
 }

运行结果:

task-0 is running.
task-1 is running.

结果说明:线程池pool的"最大池大小"和"核心池大小"都为1(THREADS_SIZE),这意味着"线程池能同时运行的任务数量最大只能是1"。

线程池pool的阻塞队列是ArrayBlockingQueue,ArrayBlockingQueue是一个有界的阻塞队列,ArrayBlockingQueue的容量为1。这也意味着线程池的阻塞队列只能有一个线程池阻塞等待。

根据""中分析的execute()代码可知:线程池中共运行了2个任务。第1个任务直接放到Worker中,通过线程去执行;第2个任务放到阻塞队列中等待。其他的任务都被丢弃了!

2. DiscardOldestPolicy 示例

 import java.lang.reflect.Field;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy;
 
 public class DiscardOldestPolicyDemo {
 
   private static final int THREADS_SIZE = 1;
   private static final int CAPACITY = 1;
 
   public static void main(String[] args) throws Exception {
 
     // 创建线程池。线程池的"最大池大小"和"核心池大小"都为1(THREADS_SIZE),"线程池"的阻塞队列容量为1(CAPACITY)。
     ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS,
         new ArrayBlockingQueue<Runnable>(CAPACITY));
     // 设置线程池的拒绝策略为"DiscardOldestPolicy"
     pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
 
     // 新建10个任务,并将它们添加到线程池中。
     for (int i = 0; i < 10; i++) {
       Runnable myrun = new MyRunnable("task-"+i);
       pool.execute(myrun);
     }
     // 关闭线程池
     pool.shutdown();
   }
 }
 
 class MyRunnable implements Runnable {
   private String name;
   public MyRunnable(String name) {
     this.name = name;
   }
   @Override
   public void run() {
     try {
       System.out.println(this.name + " is running.");
       Thread.sleep(200);
     } catch (Exception e) {
       e.printStackTrace();
     }
   }
 }

运行结果:

task-0 is running.
task-9 is running.

结果说明:将"线程池的拒绝策略"由DiscardPolicy修改为DiscardOldestPolicy之后,当有任务添加到线程池被拒绝时,线程池会丢弃阻塞队列中末尾的任务,然后将被拒绝的任务添加到末尾。 

3. AbortPolicy 示例

 import java.lang.reflect.Field;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;
 import java.util.concurrent.RejectedExecutionException;
 
 public class AbortPolicyDemo {
 
   private static final int THREADS_SIZE = 1;
   private static final int CAPACITY = 1;
 
   public static void main(String[] args) throws Exception {
 
     // 创建线程池。线程池的"最大池大小"和"核心池大小"都为1(THREADS_SIZE),"线程池"的阻塞队列容量为1(CAPACITY)。
     ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS,
         new ArrayBlockingQueue<Runnable>(CAPACITY));
     // 设置线程池的拒绝策略为"抛出异常"
     pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
 
     try {
 
       // 新建10个任务,并将它们添加到线程池中。
       for (int i = 0; i < 10; i++) {
         Runnable myrun = new MyRunnable("task-"+i);
         pool.execute(myrun);
       }
     } catch (RejectedExecutionException e) {
       e.printStackTrace();
       // 关闭线程池
       pool.shutdown();
     }
   }
 }
 
 class MyRunnable implements Runnable {
   private String name;
   public MyRunnable(String name) {
     this.name = name;
   }
   @Override
   public void run() {
     try {
       System.out.println(this.name + " is running.");
       Thread.sleep(200);
     } catch (Exception e) {
       e.printStackTrace();
     }
   }
 }

(某一次)运行结果:

java.util.concurrent.RejectedExecutionException
  at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:1774)
  at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:768)
  at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:656)
  at AbortPolicyDemo.main(AbortPolicyDemo.java:27)
task-0 is running.
task-1 is running.

结果说明:将"线程池的拒绝策略"由DiscardPolicy修改为AbortPolicy之后,当有任务添加到线程池被拒绝时,会抛出RejectedExecutionException。

4. CallerRunsPolicy 示例

 import java.lang.reflect.Field;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
 
 public class CallerRunsPolicyDemo {
 
   private static final int THREADS_SIZE = 1;
   private static final int CAPACITY = 1;
 
   public static void main(String[] args) throws Exception {
 
     // 创建线程池。线程池的"最大池大小"和"核心池大小"都为1(THREADS_SIZE),"线程池"的阻塞队列容量为1(CAPACITY)。
     ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS,
         new ArrayBlockingQueue<Runnable>(CAPACITY));
     // 设置线程池的拒绝策略为"CallerRunsPolicy"
     pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
 
     // 新建10个任务,并将它们添加到线程池中。
     for (int i = 0; i < 10; i++) {
       Runnable myrun = new MyRunnable("task-"+i);
       pool.execute(myrun);
     }
 
     // 关闭线程池
     pool.shutdown();
   }
 }
 
 class MyRunnable implements Runnable {
   private String name;
   public MyRunnable(String name) {
     this.name = name;
   }
   @Override
   public void run() {
     try {
       System.out.println(this.name + " is running.");
       Thread.sleep(100);
     } catch (Exception e) {
       e.printStackTrace();
     }
   }
 }

(某一次)运行结果:

task-2 is running.
task-3 is running.
task-4 is running.
task-5 is running.
task-6 is running.
task-7 is running.
task-8 is running.
task-9 is running.
task-0 is running.
task-1 is running.

结果说明:将"线程池的拒绝策略"由DiscardPolicy修改为CallerRunsPolicy之后,当有任务添加到线程池被拒绝时,线程池会将被拒绝的任务添加到"线程池正在运行的线程"中取运行

相关文章

  • 利用Java实现和可被K整除的子数组完整实例

    利用Java实现和可被K整除的子数组完整实例

    这篇文章主要给大家介绍了关于利用Java实现和可被K整除的子数组的相关资料,这道题来自力扣,通过学习这道题的解题思路以及代码对大家的学习或者工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2024-01-01
  • SSH框架网上商城项目第16战之Hibernate二级缓存处理首页热门显示

    SSH框架网上商城项目第16战之Hibernate二级缓存处理首页热门显示

    这篇文章主要介绍了SSH框架网上商城项目第16战之Hibernate的二级缓存处理首页的热门显示,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • Springboot实现验证码登录

    Springboot实现验证码登录

    这篇文章主要为大家详细介绍了Springboot实现验证码登录,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • SpringBoot根据各地区时间设置接口有效时间的实现方式

    SpringBoot根据各地区时间设置接口有效时间的实现方式

    这篇文章给大家介绍了SpringBoot根据各地区时间设置接口有效时间的实现方式,文中通过代码示例给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-01-01
  • Feign如何设置超时时间(不同情况)

    Feign如何设置超时时间(不同情况)

    本文主要介绍了Feign的超时时间设置,包括单独使用Feign和在SpringCloud环境下的设置方式,以及与Ribbon和Hystrix的配合使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-11-11
  • Spring Cache的基本使用与实现原理详解

    Spring Cache的基本使用与实现原理详解

    缓存是实际工作中非经常常使用的一种提高性能的方法, 我们会在很多场景下来使用缓存。下面这篇文章主要给大家介绍了关于Spring Cache的基本使用与实现原理的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2018-05-05
  • Java对称与非对称加密算法原理详细讲解

    Java对称与非对称加密算法原理详细讲解

    对称加密算法指加密和解密使用相同密钥的加密算法。对称加密算法用来对敏感数据等信息进行加密,非对称加密算法指加密和解密使用不同密钥的加密算法,也称为公私钥加密
    2022-11-11
  • MybatisGenerator文件生成不出对应文件的问题

    MybatisGenerator文件生成不出对应文件的问题

    本文介绍了使用MybatisGenerator生成文件时遇到的问题及解决方法,主要步骤包括检查目标表是否存在、是否能连接到数据库、配置生成器的路径等,通过在项目结构中引入相应的jar包,并在GeneratorSqlmap.java文件中运行,可以成功生成对应的文件
    2025-01-01
  • mybatis初始化SqlSessionFactory失败的几个原因分析

    mybatis初始化SqlSessionFactory失败的几个原因分析

    这篇文章主要介绍了mybatis初始化SqlSessionFactory失败的几个原因分析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Spring实现处理跨域请求代码详解

    Spring实现处理跨域请求代码详解

    这篇文章主要介绍了Spring实现处理跨域请求代码详解,具有一定借鉴价值,需要的朋友可以了解下。
    2017-12-12

最新评论