先看几段代码吧!
代码一:
public class TestMultiThread2 implements Runnable{ private static Object o = new Object(); private static Integer si = 0; private static AtomicInteger flag = new AtomicInteger(); @Override public void run() { for(int k=0;k<2000000;k++){ synchronized(si){ si++; } } flag.incrementAndGet(); } public static void main(String[] args) throws InterruptedException{ TestMultiThread2 t1 = new TestMultiThread2(); TestMultiThread2 t2 = new TestMultiThread2(); ExecutorService exec1 = Executors.newCachedThreadPool(); ExecutorService exec2 = Executors.newCachedThreadPool(); exec1.execute(t1); exec2.execute(t2); while(true){ if(flag.intValue()==2){ System.out.println("si>>>>>"+si); break; } Thread.sleep(50); } } }
为了方便看,重复的就不插入了,从代码二到代码四只插入run()方法中的代码,其他地方都一样
代码二:
public void run() { for(int k=0;k<2000000;k++){ synchronized(o){ si++; } } flag.incrementAndGet(); }
代码三:
public void run() { for(int k=0;k<2000000;k++){ synchronized(o){ si++; o = new Object(); } } flag.incrementAndGet(); }
代码四:
public void run() { for(int k=0;k<2000000;k++){ synchronized(o){ si++; Object temp = o; o = new Object(); o = temp; } } flag.incrementAndGet(); }
有了这四段代码我想问题大概可以说明白了,这里说一下输出吧。
代码一:<4000000
代码二:=4000000
代码三:<4000000
代码四:<4000000(PS:这个结果非常接近4000000)
这里说明一下我测试中碰到的问题,代码四一直没有跑出我想要的结果,主要是开始我设的循环次数太少,其实这里如果要这个现象更加明显一些可以在中间多new 几个Object 如下面的代码五,这样现象就比较明显了.
代码五:
public void run() { for(int k=0;k<2000000;k++){ synchronized(o){ si++; Object temp = o; for(int m=0;m<10;m++){ o = new Object(); } o = temp; } } flag.incrementAndGet(); }
为什么会出现上面的现象:
代码一:当si做++操作后(可以直接看字节码,这里不贴了),在putstatic之前有几步操作,就是我们常说的非原子操作,而这时候si已经不是原来的对象了,这样锁对另外一个线程来说就失效了,我想代码三和代码四就是最好的佐证,代码四更有说服力。当时因为没有出现预想的情况困惑了挺久。
其实这里用字节码来解释还不是很严谨,最好的当然直接是汇编代码
如有什么问题还希望各位读者指正。