今天学习了java的并发,线程池,同一时间执行一个操作。

报错:java.util.concurrent.RejectedExecutionException,排查发现是等待队列设小了,导致

拒绝策略,当队列满时,处理策略报错异常。

上代码:

package aqs;import java.util.concurrent.*;/*** @author WHM* 实现指定时间内做一定事情* @date 2021年08月06日 16:27*/
public class CountDownLatchTest {public static int clientTotal = 2000;// 核心线程数,当线程池空闲时保留的线程数static int corePoolSize = 2;// 线程池最大线程数,线程池繁忙时能够扩容到的最大线程数static int maximumPoolSize = 5;// 线程活跃时间,当线程数大于核心数时,并且线程开始空闲,此时多余的线程经过活跃时间后自动关闭static int keepAliveTime = 1;// 线程活跃时间单位static TimeUnit unit = TimeUnit.SECONDS;static BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(20); // 等待队列,ArrayBlockingQueue为有界阻塞队列,当队列满时进行阻塞static RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); // 拒绝策略,当队列满时,处理策略static ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, queue, handler);public static void main(String[] args) throws  Exception{final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);for(int i = 0;i < clientTotal; i++) {final int now = i;executor.execute(()->{try{test(now);} catch (Exception e) {e.printStackTrace();} finally {countDownLatch.countDown();}});}countDownLatch.await(5, TimeUnit.SECONDS);System.out.println("thread finish");executor.shutdown();}private static void test(final int threadNum) throws Exception {Thread.sleep(3000);System.out.println("thread: {}" + threadNum);}
}

本来以为写的还不错的代码执行报错了:

分析
通过对ThreadPoolExecutor类分析,引发java.util.concurrent.RejectedExecutionException主要有两种原因:
1. 线程池显示的调用了shutdown()之后,再向线程池提交任务的时候,如果你配置的拒绝策略是ThreadPoolExecutor.AbortPolicy的话,这个异常就被会抛出来。
2. 当你的排队策略为有界队列,并且配置的拒绝策略是ThreadPoolExecutor.AbortPolicy,当线程池的线程数量已经达到了maximumPoolSize的时候,你再向它提交任务,就会抛出ThreadPoolExecutor.AbortPolicy异常。 (我们设定了)

static BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(20); 但是线程有2000个

所以,被拒绝啦。

对于分析的第一个我们可以做个例子:

这一点很好理解。比如说,你向一个仓库去存放货物,一开始,仓库管理员把门给你打开了,你放了第一件商品到仓库里,但是当你放好出去后,有人把仓库门关了,那你下次再来存放物品时,你就会被拒绝。示例代码如下:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class TextExecutor {public ExecutorService fixedExecutorService = Executors.newFixedThreadPool(5);public ExecutorService cachedExecutorService = Executors.newCachedThreadPool();public ExecutorService singleExecutorService = Executors.newSingleThreadExecutor();public void testExecutorException() {for (int i = 0; i < 10; i ++) {fixedExecutorService.execute(new SayHelloRunnable());fixedExecutorService.shutdown();}}private class SayHelloRunnable implements Runnable {@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {System.out.println("hello world!");}}}public static void main(String[] args) {TextExecutor testExecutor = new TextExecutor();testExecutor.testExecutorException();}
}

解决方案
1. 不要显示的调用shutdown方法,例如Android里,只有你在Destory方法里cancel掉AsyncTask,则线程池里没有活跃线程会自己回收自己。
2. 调用线程池时,判断是否已经shutdown,通过API方法isShutDown方法判断,示例代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class TextExecutor {public ExecutorService fixedExecutorService = Executors.newFixedThreadPool(5);public ExecutorService cachedExecutorService = Executors.newCachedThreadPool();public ExecutorService singleExecutorService = Executors.newSingleThreadExecutor();public void testExecutorException() {for (int i = 0; i < 10; i ++) {// 增加isShutdown()判断if (!fixedExecutorService.isShutdown()) {fixedExecutorService.execute(new SayHelloRunnable());}fixedExecutorService.shutdown();}}private class SayHelloRunnable implements Runnable {@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {System.out.println("hello world!");}}}public static void main(String[] args) {TextExecutor testExecutor = new TextExecutor();testExecutor.testExecutorException();}
}

第二种报错代码已经给出:

我们看如何解决:

1.提大排队队列

static BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2000);

2.使用LinkedBlockingQueue

static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();

问题延伸

1.不建议使用Executors创建线程

较为方便的Executors工厂方法Executors.newCachedThreadPool() (无界线程池,可以进行自动线程回收)、Executors.newFixedThreadPool(int)(固定大小线程池)和Executors.newSingleThreadExecutor()(单个后台线程),但是通过源码我们可以发现最后他们均调用了ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) 方法,因此我们在分析java.util.concurrent.RejectedExecutionException之前,需要深入学习一下ThreadPoolExecutor的使用。

2.了解一下:TreadPoolExecutor

核心池和最大池的大小
TreadPoolExecutor将根据corePoolSize和maximumPoolSize设置的边界自动调整池大小。当新任务在方法execute(java.lang.Runnable)中提交时,如果运行的线程少于corePoolSize,则创建新线程来处理请求,即使其他辅助线程是空闲的。如果运行的线程多于corePoolSize而少于maximumPoolSize,则仅当队列满时才创建新的线程。如果设置的corePoolSize和maximumPoolSize相同,则创建了固定大小的线程池。如果将maximumPoolSize设置为基本的无界值(如Integer.MAX_VALUE),则允许线程池适应任意数量的并发任务。

3. BlockingQueue/LinkedBlockingQueue我们通过异同快速了解一下:

相同:

1、LinkedBlockingQueue和ArrayBlockingQueue都实现了BlockingQueue接口;

2、LinkedBlockingQueue和ArrayBlockingQueue都是可阻塞的队列

  内部都是使用ReentrantLock和Condition来保证生产和消费的同步;

  当队列为空,消费者线程被阻塞;当队列装满,生产者线程被阻塞;

使用Condition的方法来同步和通信:await()和signal()

不同:

1、由上图可以看出,他们的锁机制不同

  LinkedBlockingQueue中的锁是分离的,生产者的锁PutLock,消费者的锁takeLock

  而ArrayBlockingQueue生产者和消费者使用的是同一把锁;

2、他们的底层实现机制也不同

  LinkedBlockingQueue内部维护的是一个链表结构

在生产和消费的时候,需要创建Node对象进行插入或移除,大批量数据的系统中,其对于GC的压力会比较大

  而ArrayBlockingQueue内部维护了一个数组

在生产和消费的时候,是直接将枚举对象插入或移除的,不会产生或销毁任何额外的对象实例

3、构造时候的区别

  LinkedBlockingQueue有默认的容量大小为:Integer.MAX_VALUE,当然也可以传入指定的容量大小

ArrayBlockingQueue在初始化的时候,必须传入一个容量大小的值

  看其提供的构造方法就能知道 (ideaALT+7 可以查看类方法)

4、执行clear()方法

  LinkedBlockingQueue执行clear方法时,会加上两把锁

要问什么锁,想想,肯定是生产/消费锁

ArrayBlockingQueue是添加一把锁

5、统计元素的个数

  LinkedBlockingQueue中使用了一个AtomicInteger对象来统计元素的个数

毕竟有2个锁,所以保障count的原子性,需要使用AtomicInteger来控制,底层使用CAS来控制同步。  好烦是不是又要看CAS (之前有写过一篇哦)

ArrayBlockingQueue则使用int类型来统计元素

作为开发者,我们需要注意的是,如果构造一个LinkedBlockingQueue对象,而没有指定其容量大小,LinkedBlockingQueue会默认一个类似无限大小的容量(Integer.MAX_VALUE),这样的话,如果生产者的速度一旦大于消费者的速度,也许还没有等到队列满阻塞产生,系统内存就有可能已被消耗殆尽了。

1]解决java.util.concurrent.RejectedExecutionException相关推荐

  1. 【ruoyi】java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.ScheduledThreadPoo

    前言 ruoyi 4.6.0 jdk1.8 错误 11:48:16.879 [http-nio-9031-exec-25] INFO c.r.f.s.r.UserRealm - [doGetAuthe ...

  2. java.util.concurrent.RejectedExecutionException

    2019独角兽企业重金招聘Python工程师标准>>> 遇到java.util.concurrent.RejectedExecutionException 目前看来,最主要有2种原因 ...

  3. java.util.concurrent.RejectedExecutionException: event executor terminated 错误分析

    java.util.concurrent.RejectedExecutionException: event executor terminated 错误分析

  4. 关于java.util.concurrent.RejectedExecutionException: event executor terminated

    多线程报了个java.util.concurrent.RejectedExecutionException: event executor terminated 线程池的拒绝策略 ThreadPool ...

  5. 已解决java.util.concurrent.ExecutionException异常的正确解决方法,亲测有效!!!

    已解决java.util.concurrent.ExecutionException异常的正确解决方法,亲测有效!!! 文章目录 报错问题 解决方法 福利 报错问题 粉丝群里面的一个小伙伴敲代码时发生 ...

  6. 线程池java.util.concurrent.ThreadPoolExecutor总结

    http://uule.iteye.com/blog/1123185 线程池还具有提高系统性能的优点,因为创建线程和清除线程的开销比较大. 有两种不同类型的线程池:一是固定线程数量的线程池:二是可变数 ...

  7. rejected from java.util.concurrent.ThreadPoolExe错误

    2019独角兽企业重金招聘Python工程师标准>>> java.util.concurrent.RejectedExecutionException: Task com.dangd ...

  8. 线程池(java.util.concurrent.ThreadPoolExecutor)的使用

    如果大家觉得这个类还不能完全满足自己的要求的话,其实可以照搬这个源码,然后适当改动一下来适合自己的需求,也不失为一种捷径的.呵呵,本人最近在自己做的一个项目中,就来了这一手.虽然不是多好,主要是为了满 ...

  9. java util下的并发包_jdk并发包下:使用java.util.concurrent.Executor线程池

    多线程,线程池Executor的接口类图: 其他都不重要,就ExecutorService是主要的: 基本上分为单纯线程池和定时任务线程池: 说白了除了ForkJoinPool所有都继承于Thread ...

最新文章

  1. tensorflow tf.keras.losses.MeanSquaredError 均方差损失函数 示例
  2. Semver(语义化版本号)扫盲
  3. 移动磁盘格式化了,要如何寻回数据
  4. win10 linux子系统ssh,win10 子系统 bash 不能监听端口
  5. ElasticSearch第一天
  6. Web Hacking 101 中文版 十、跨站脚本攻击(一)
  7. JavaScript变量提升:函数提升要比变量提升更猛
  8. Python爬虫编程实践 Task04
  9. 离散分布的分布函数_数据分析|概率分布
  10. Sublime安装中文插件
  11. memcacheQueue队列
  12. 计算机启动项在什么地方找,电脑开机启动项在哪里设置
  13. 基于python语言设计的词云定制器
  14. 计算机32位操作系统指什么,电脑操作系统的32位和64位有什么区别
  15. coding码市提交代码
  16. 计算机上做报纸模板,word中怎么制作报纸排版模板
  17. c语言函数大全 pdf,C语言标准库函数大全.pdf
  18. 张裕公司创始人张弼士与李鸿章的交往
  19. DHCP,DNS,以及网关的意思和存在意义
  20. 三维数据入到arcgis平台的解决方案

热门文章

  1. 去掉input text边框
  2. cadence原理图复用_详细了解一下Allegro原理图设计工具SDA 的十大主要功能和改变...
  3. python使用大漠插件教程_python调用大漠插件教程04鼠键事件及基本项目思维
  4. Convolutional Neural Network
  5. CLR的主要作用有哪些
  6. 稀疏编码器(Sparse Encoder)
  7. KVM is required to run this AVD /dev/kvm permission denied Ubuntu Android Studio
  8. linux下的lib文件知识
  9. python-爬取图片
  10. 作为喜爱3D游戏动漫建模的你,如果还不知道次世代游戏贴图的这些技巧,真是太可惜了