• [置顶] 深入探析Java线程锁机制


    今天在iteye上提了一个关于++操作和线程安全的问题,一位朋友的回答一言点醒梦中人,至此我对Java线程锁有了更加深刻的认识。在这里也做个总结供大家参考。

          先看几段代码吧!

       代码一:

    1. public class TestMultiThread2 implements Runnable{  
    2.   
    3.     private static Object o = new Object();  
    4.       
    5.     private static Integer si = 0;  
    6.       
    7.     private static AtomicInteger flag = new AtomicInteger();  
    8.       
    9.     @Override  
    10.     public void run() {  
    11.         for(int k=0;k<2000000;k++){  
    12.             synchronized(si){  
    13.                 si++;  
    14.             }  
    15.         }  
    16.         flag.incrementAndGet();  
    17.     }  
    18.     public static void main(String[] args) throws InterruptedException{  
    19.         TestMultiThread2 t1 = new TestMultiThread2();  
    20.         TestMultiThread2 t2 = new TestMultiThread2();  
    21.         ExecutorService exec1 = Executors.newCachedThreadPool();  
    22.         ExecutorService exec2 = Executors.newCachedThreadPool();  
    23.         exec1.execute(t1);  
    24.         exec2.execute(t2);  
    25.         while(true){  
    26.             if(flag.intValue()==2){  
    27.                 System.out.println("si>>>>>"+si);      
    28.                 break;  
    29.             }  
    30.             Thread.sleep(50);  
    31.         }  
    32.   
    33.           
    34.     }     
    35.       
    36. }  

       为了方便看,重复的就不插入了,从代码二到代码四只插入run()方法中的代码,其他地方都一样

      代码二:

    1. public void run() {    
    2.     for(int k=0;k<2000000;k++){    
    3.         synchronized(o){    
    4.             si++;    
    5.         }    
    6.     }    
    7.     flag.incrementAndGet();    
    8. }    

      代码三:

    1. public void run() {    
    2.     for(int k=0;k<2000000;k++){    
    3.         synchronized(o){    
    4.             si++;    
    5.             o = new Object();    
    6.         }    
    7.     }    
    8.     flag.incrementAndGet();    
    9. }    

        代码四: 

    1. public void run() {    
    2.      for(int k=0;k<2000000;k++){    
    3.          synchronized(o){    
    4.              si++;    
    5.              Object temp = o;    
    6.              o = new Object();    
    7.              o = temp;    
    8.          }    
    9.      }    
    10.      flag.incrementAndGet();    
    11.  }    

      有了这四段代码我想问题大概可以说明白了,这里说一下输出吧。

      代码一:<4000000

      代码二:=4000000

      代码三:<4000000

      代码四:<4000000(PS:这个结果非常接近4000000)

          这里说明一下我测试中碰到的问题,代码四一直没有跑出我想要的结果,主要是开始我设的循环次数太少,其实这里如果要这个现象更加明显一些可以在中间多new 几个Object 如下面的代码五,这样现象就比较明显了.

      代码五:

    1. public void run() {    
    2.     for(int k=0;k<2000000;k++){    
    3.         synchronized(o){    
    4.             si++;    
    5.             Object temp = o;    
    6.             for(int m=0;m<10;m++){    
    7.                 o = new Object();    
    8.             }    
    9.             o = temp;    
    10.         }    
    11.     }    
    12.     flag.incrementAndGet();    
    13. }    

     为什么会出现上面的现象:

         代码一:当si做++操作后(可以直接看字节码,这里不贴了),在putstatic之前有几步操作,就是我们常说的非原子操作,而这时候si已经不是原来的对象了,这样锁对另外一个线程来说就失效了,我想代码三和代码四就是最好的佐证,代码四更有说服力。当时因为没有出现预想的情况困惑了挺久。

        其实这里用字节码来解释还不是很严谨,最好的当然直接是汇编代码

        如有什么问题还希望各位读者指正。

    zhuanzi:http://blog.csdn.net/luohuacanyue/article/details/8307617

  • 相关阅读:
    Python 入门变量类型标识符和关键字
    对于msSql中exists操作符求值的疑惑
    那个蛋痛的list的remove_if中用到的对像函数
    继承一个虚类的时候要小心是,并使其实例化时.必须使其全实重写了纯虚的方法...类定义的位置
    MSSQL(TSQL)中的varchar不指定大小好像一般来说只有一个的长度
    关于TSQL中触发器的只言片语
    MSSQL十秒一次的job
    用了Rime输入法之后,发现IE要关闭保护模式才能输入
    三性原则,指的是商业银行的“安全性、流动性、效益性
    九选三
  • 原文地址:https://www.cnblogs.com/pricks/p/3877133.html
Copyright © 2020-2023  润新知