使用Boolean类型同步锁引起异常的分析
2023-09-27 14:24:49 时间
原文地址 http://topic.csdn.net/u/20080710/19/f61cb4db-ddff-4457-a26a-4ea578b0cc6c.html?87447500 http://www.java2000.net/viewthread.jsp?tid=7085
提问:【tteesstt】
- public class MyTest {
- public static void main(String[] args) throws Exception {
- new TestThread().start();
- new TestThread().start();
- Thread.sleep(1000);
- System.out.println("Doing something...");
- synchronized (lock) {
- lock = false; // 语句1
- lock.notifyAll(); // 语句2
- }
- }
- static volatile Boolean lock = true;
- }
-
- class TestThread extends Thread {
- @Override
- public void run() {
- synchronized (MyTest.lock) {
- while (MyTest.lock) {
- try {
- MyTest.lock.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- System.out.println(getId());
- }
- }
- }
输出结果为
Doing something...
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at MyTest.test(MyTest.java:13)
at MyTest.main(MyTest.java:3
如果把语句1和语句2调换一下就正常了。 大家给诊断一下,到底是为什么?
讨论过程请大家自行参考原始的帖子和我的整理帖子,这里只给出最终的分析结果
分析:
当作为同步锁的对象发生改变时,比如换了一个新的对象,那么如果在新的对象上调用同步的wait等方法,由于并没有同步这个对象,而是同步的改变以前的那个,就会报出如上的异常。 我们来看代码
- synchronized (lock) {
- lock = false; // 语句1
- lock.notifyAll(); // 语句2
- }
语句1那里修改了lock的对象指向,结果造成下面的一句notifyAll使用了一个并没有synchronized的对象,随意报出了异常。
解决方法
方案1,使用Boolean的特殊性 由于 lock=false;的特殊性,分析Boolean的源代码发现
- public static final Boolean TRUE = new Boolean(true);
- public static final Boolean FALSE = new Boolean(false);
- public static Boolean valueOf(boolean b) {
- return (b ? TRUE : FALSE);
- }
-
- //发现其内部对于自动打包,拆包只使用了2个固定的对象。所以可以用
-
- synchronized (lock) {
- lock = false; // 语句1
- Boolean.TRUE.notifyAll(); // 语句2
- }
-
- // 直接使用那个TRUE就行了。
方法2:使用一个参数可变对象,而不是不可变的,
比如
class MyLock {
boolean lock = true;
}
static volatile MyLock lock = new MyLock();
// 然后再代码里面用
lock.lock=false;// 进行标志的变更和判断就可以了
结论:
同步锁最好单独使用,如果锁自身附带了其它作用,应使用一个可变的对象 推荐
static volatile MyLock lock = new MyLock();
应该写成
final static volatile MyLock lock = new MyLock();
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
相关文章
- iOS阻止文件被iTunes和iCloud同步
- 深入理解MVC C#+HtmlAgilityPack+Dapper走一波爬虫 StackExchange.Redis 二次封装 C# WPF 用MediaElement控件实现视频循环播放 net 异步与同步
- (转)主从同步遇到 Got fatal error 1236 from master when reading data from binary log: 'Could not find first log...
- 阿里云大数据工厂DataWorks学习之--数据同步任务常见日志报错总结
- Rsync+inotify 实时数据同步 inotify master 端的配置
- TA(App总启动时间) = T1(main()之前的加载时间 进程构建时间) + T2(main()之后的加载时间 运行环境准备时间) +T3(首页数据加载+闪屏页数据同步) 应用时间
- 同步和异步关注的是消息通信机制,阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态
- 2.Emwin的数字键盘输入到Edit窗口更新以及到另一个页面Text控件的值并且同步改变。
- CreateFile()----同步
- rsync+inotify实现实时同步案例--转
- 使用rsync快速同步远程文件目录
- Windows线程同步——临界区对象
- react中setState()是异步的还是同步的,如何控制?
- 同步、异步的使用场景及好处
- VSCode 本地远程同步