并发编程中的一致性问题:ForkJoinPool调用shutdown的bug.(jdk8&jdk9)
来源:互联网 发布:linux 查看用户 编辑:程序博客网 时间:2024/06/05 02:19
ForkJoinPool调用shutdown从而终止整个并发执行框架。
包括取消所有队列中已有的任务,终止所有的工作线程。
考虑这样一个场景,一个线程正在提交任务,另一个线程正在调用shutdown终止线程池。
此时涉及到3个独立的执行逻辑:
- 调用pool.submit的线程
- 调用pool.shutdown()的线程
- 线程池中的工作线程
由于这三个独立的执行逻辑,必须就线程池将(SHUTDOWN)这一状态达成共识。有没有可能会产生不一致的状态,从而导致丢失信号呢?
在当前的jdk8中的实现存在这个bug,JDK 9 Early-Access中也存在这个问题,只是重现方法不同,见下文。
我们使用如下的test case(jdk8):
package com.psly;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ForkJoinPool;import java.util.concurrent.ForkJoinTask;public class TestForkJoin {public static void main(String[] args) throws InterruptedException {// TODO Auto-generated method stubForkJoinPool pool = new ForkJoinPool();new Thread(){public void run(){ForkJoinTask<String> task = pool.submit(new Callable<String>(){public String call(){return "Hello,world";}});//输出 Hello,world (永远不会输出,也不会报异常, 所以这是个bug)try {System.out.println(task.get());} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ExecutionException e) {// TODO Auto-generated catch blocke.printStackTrace();}}{ this.setName("printHelloWorld");this.start(); }};//Thread.sleep(1000);new Thread(){public void run(){pool.shutdown();}{ this.setName("shutdownPool");this.start(); }};}}执行以上代码,输出为:
Exception in thread "printHelloWorld" java.util.concurrent.RejectedExecutionExceptionat java.util.concurrent.ForkJoinPool.externalSubmit(ForkJoinPool.java:2328)at java.util.concurrent.ForkJoinPool.externalPush(ForkJoinPool.java:2419)at java.util.concurrent.ForkJoinPool.submit(ForkJoinPool.java:2675)at com.psly.TestForkJoin$1.run(TestForkJoin.java:14)任务被拒绝,这是一个可接受的结果。
//Thread.sleep(1000);我们去除这一句注释,让shutdown线程晚1秒一点执行。
再次执行,输出为:
Hello,world这同样是一个可以接受的结果。
也就是线程池,面对提交的一个任务,要么执行它,要么拒绝它,不能永远什么都不做。
我们接着在jdk8中,如下两行(2359&2224)打上断点:
2359 U.putOrderedObject(a, j, task); 2224 rs = lockRunState(); // enter SHUTDOWN phase
然后再次注释Thread.sleep(1000)。
//Thread.sleep(1000);
debug我们一开始给出的test case。
然后shutdownPool线程在2224行上挂起,printHelloWorld线程在2359行上挂起。我们先让shutdownPool通过,再让printHelloWorld线程通过。
此时会看到我们的程序没有任何输出,并且printHelloWorld线程永远挂起了。
一个解决方案是在2359行,也就是将任务放入队列之后再次检查下SHUTDOWN状态是否被设置,假如是的话尝试将任务重新删除。
jdk9中的实现与8已经不一样了。详情可见点击打开链接
阅读全文
0 0
- 并发编程中的一致性问题:ForkJoinPool调用shutdown的bug.(jdk8&jdk9)
- 并发编程中的CyclicBarrier之shutdown()与shutdownNow()的区别!
- 并发操作的一致性问题
- 数据库并发操作的一致性问题
- 数据库并发操作的一致性问题
- 并发一致性问题
- 【4】Java并发编程:多线程中的缓存一致性和CAS
- 第2章 并发操作的一致性问题 (1)
- TCP编程中的shutdown和close的区别
- tomcat shutdown的问题:
- 聊聊高并发(五)理解缓存一致性协议以及对并发编程的影响
- 关于tcp套接字中的的shutdown问题
- 关于jdk7的forkjoinpool
- ForkJoinPool的使用
- JDK8对并发的新支持
- JDK8对并发的新支持
- 【Java并发编程】内存一致性错误
- 传说中的并发编程ABA问题
- MATLAB读取Excel表格数据,将不同数据绘制在同一散点图中
- Newton法(牛顿法 Newton Method)
- centos7重启网络报错"Job for network.service failed"
- 一个经典的例子让你彻底理解Java回调机制
- [BZOJ]2809: [Apio2012]dispatching 主席树(线段树合并)
- 并发编程中的一致性问题:ForkJoinPool调用shutdown的bug.(jdk8&jdk9)
- powershell部署Azure云虚拟机的命令流程
- Keras实现LSTM
- android Error:Execution failed for task ':app:transformClassesWithJarMergingForRelease'
- 前端零基础入门(五):如何在页面当中引用css样式
- 数据库数据采集总结
- UBUNTU14.04-CUDA 7.5安装
- redis | list命令
- Appium简介