zoukankan      html  css  js  c++  java
  • 使用Boolean类型同步锁引起异常的分析

    原文地址 http://topic.csdn.net/u/20080710/19/f61cb4db-ddff-4457-a26a-4ea578b0cc6c.html?87447500 http://www.java2000.net/viewthread.jsp?tid=7085

    提问:【tteesstt

    1. public class MyTest {
    2. public static void main(String[] args) throws Exception {
    3. new TestThread().start();
    4. new TestThread().start();
    5. Thread.sleep(1000);
    6. System.out.println("Doing something...");
    7. synchronized (lock) {
    8. lock = false; // 语句1
    9. lock.notifyAll(); // 语句2
    10. }
    11. }
    12. static volatile Boolean lock = true;
    13. }
    14. class TestThread extends Thread {
    15. @Override
    16. public void run() {
    17. synchronized (MyTest.lock) {
    18. while (MyTest.lock) {
    19. try {
    20. MyTest.lock.wait();
    21. } catch (InterruptedException e) {
    22. e.printStackTrace();
    23. }
    24. }
    25. System.out.println(getId());
    26. }
    27. }
    28. }
    输出结果为
    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等方法,由于并没有同步这个对象,而是同步的改变以前的那个,就会报出如上的异常。 我们来看代码
    1. synchronized (lock) {
    2. lock = false; // 语句1
    3. lock.notifyAll(); // 语句2
    4. }

    语句1那里修改了lock的对象指向,结果造成下面的一句notifyAll使用了一个并没有synchronized的对象,随意报出了异常。

    解决方法

    方案1,使用Boolean的特殊性 由于 lock=false;的特殊性,分析Boolean的源代码发现

    1. public static final Boolean TRUE = new Boolean(true);
    2. public static final Boolean FALSE = new Boolean(false);
    3. public static Boolean valueOf(boolean b) {
    4. return (b ? TRUE : FALSE);
    5. }
    6. //发现其内部对于自动打包,拆包只使用了2个固定的对象。所以可以用
    7. synchronized (lock) {
    8. lock = false; // 语句1
    9. Boolean.TRUE.notifyAll(); // 语句2
    10. }
    11. // 直接使用那个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>
  • 相关阅读:
    趣谈编程史第4期-饱受争议的前端之王JavaScript的血泪成长史
    趣谈编程史第2期-这个世界缺少对C语言的敬畏,你不了解的C语言科普
    趣谈编程史第1期-跌宕起伏的java帝国史,剖析谷歌甲骨文长达8年的版权战争
    记录一次Metaspace扩容引发FGC的调优总结
    多线程学习笔记-深入理解ThreadPoolExecutor
    使用CompletableFuture优化你的代码执行效率
    Linux+Shell常用命令总结
    Guava Cache探索及spring项目整合GuavaCache实例
    将List按照指定大小等分的几种实现方式和效率对比及优化
    Spring的事件机制详解
  • 原文地址:https://www.cnblogs.com/jpfss/p/9620187.html
Copyright © 2011-2022 走看看