看这么一段代码,思考为什么结果不是0?
publicclassSyncDemo{privatestaticintcount=0;publicstaticvoidincrement(){count++;}publicstaticvoiddecrement(){count--;}publicstaticvoidmain(String[]args)throwsInterruptedException{Threadt1=newThread(()-{for(inti=0;i;i++){increment();}},"t1");Threadt2=newThread(()-{for(inti=0;i;i++){decrement();}},"t2");t1.start();t2.start();t1.join();t2.join();System.out.println(count);}}
问题分析
Java中对静态变量的自增,自减并不是原子操作。
i++的JVM字节码指令
getstatici//获取静态变量i的值iconst_1//将int常量1压入操作数栈iadd//自增
i--的JVM字节码指令
getstatici//获取静态变量i的值iconst_1//将int常量1压入操作数栈isub//自减
临界区(CriticalSection)
我们知道一个程序可以运行多个线程是没有任何问题的。但是多个线程去读共享资源,也是没有问题的!在多个线程对共享资源读写操作时发生指令交错,就会出现问题!一段代码块内如果存在对共享资源的多线程读写操作,称这段代码块为临界区,其共享资源为临界资源。往简单说,上面的i--与i++的代码块就是临界区。
竞态条件(RaceCondition)
多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件。阻塞式的解决方案:synchronized,Lock非阻塞式的解决方案:原子变量
synchronized解决结果不为0的问题
第一种方式
publicsynchronizedstaticvoidincrement(){count++;}publicstaticsynchronizedvoiddecrement(){count--;}
第二种方式
privatestaticStringlock="";publicstaticvoidincrement(){synchronized(lock){count++;}}publicstaticvoiddecrement(){synchronized(lock){count--;}}
不同位置的synchronized有什么区别呢?
image.png
结束语
本文只说synchronized的基础使用。深入研究请