CSDN|Semaphore 里面居然有这么一个大坑!( 五 )
threadA.start;
threadC.start;
threadB.start;
//模拟大爷劝退
threadB.interrupt;
}
}
privateintn;
}
@Override
System.out.println(Thread.currentThread.getName +"把自己的"+ carName +"停进来了,"+"剩余停车位:"+ semaphore.availablePermits +"辆");
//模拟停车时长
}catch(InterruptedException e) {
System.err.println(Thread.currentThread.getName +"被门口大爷劝走了 。 ");
}finally{
}
}
}
看着代码是没有毛病 , 但是运行起来你会发现 , 有可能出现这样的情况: why哥走后 , 剩余停车位变成了 5 辆?我是开着劳斯莱斯去给他们开发停车位去了吗? 在往前看日志发现 , 原来是刘能、谢广坤走后 , 显示了剩余停车位 3 辆 。问题就出在这个地方 。而这个地方对应的代码是这样的: 有没有一点恍然大悟的感觉 。50 行抛出了 InterruptedException , 导致明明没有获取到许可证的线程 , 执行了 release 方法 , 而该方法导致许可证增加 。在我们的例子里面就是刘能、谢广坤的车都还没停进去 , 走的时候门口的显示屏就增加了两个停车位 。这就是坑 , 就是你代码中的 BUG 潜伏地带 。而且还非常的危险 , 你想你代码里面莫名其妙的多了几个“许可证” 。 就意味着可能又多于你预期的线程在运行 。 很危险 。那么怎么修复呢? 答案已经呼之欲出了,这个地方需要 catch 起来 , 如果出现中断异常 , 直接返回: 跑起来 , 结果也正确 , 所有车都走了后 , 停车位还是只有 3 辆: 上面的写法还有一个疑问 , 如果我刚刚拿到许可证 , 就被中断了 , 怎么办? 看源码啊 , 源码里面有答案的 。 抛出 InterruptedException 后 , 分配给这个线程的所有许可证都会被分配给其他想要获取许可证的线程 , 就像通过调用 release 方法一样 。
增强release 你分析上面的问题会发现 , 导致问题的原因是没有获取到许可证的线程 , 调用了 release 方法 。我觉得这个设定 , 就是非常容易踩坑的地方 。 简直就是一个大坑! 我们可以就这个问题 , 对 release 方法进行增强 , 只有获取后的线程 , 才能调用 release 方法 。这一招我是在《Java高并发编程详解-深入理解并发核心库》里面学到的: 其中的 3.4.4 小节《扩展 Semaphore 增强 release》: 获取许可证的方法被修改成这样了(我只截取其中一个方法) , 获取成功后放入到队列里面:
本文插图
里面的 release 方法修改成这样了 , 执行之前先看看当前线程是否是在队列里面:
推荐阅读
- 青年|为什么花呗之前要10号还款?里面的套路竟然第一次知道
- 手机使用技巧|手机变慢了,是里面垃圾太多了,那么怎样清理手机垃圾呢?
- 地球|地心的温度,达到了太阳表面的温度,里面会存在着什么物质
- 互联网|购买手机,你是选择实体店还是网上,敢在拼多多里面买手机吗?
- CSDN|三次改变世界、却被无情出局的程序员
- CSDN|机器学习将会如何影响软件开发和测试?看完这文就懂了
- CSDN|语雀的技术架构演进之路
- CSDN|字节跳动、腾讯回应美国政府行政命令;英特尔回应20GB机密文档被泄露;优麒麟20.04.1发布|极客头条
- CSDNTB|监控系统选型,这篇不可不读
- CSDN|知乎技术热帖:Qt 这么强大为什么火不起来?