java虛擬機提供的輕量級的同步機制java
安全
程,就會獲得通知多線程
1 class Mydata{ 2 volatile int a=0; 3 public void resizeA() { 4 this.a=60; 5 } 6 } 7 public class VolatileDemo { 8 public static void main(String[] args) { 9 Mydata mydata = new Mydata(); 10 new Thread(()->{ 11 System.out.println(Thread.currentThread().getName()+"\t com in"); 12 try { 13 TimeUnit.SECONDS.sleep(3);//延遲3秒 14 }catch (InterruptedException e){ 15 e.printStackTrace(); 16 } 17 mydata.resizeA(); 18 System.out.println(Thread.currentThread().getName()+"\t updata number value:"+mydata.a); 19 },"aaa").start(); 20 21 while (mydata.a == 0) { 22 //等待 23 } 24 System.out.println(Thread.currentThread().getName()+"\t over"+mydata.a); 25 } 26 27 }
不加volatile 結果1性能
aaa com inthis
aaa updata number value:60spa
不加volatile 線程main 獲得的值一直是a=0,因此一直套在死循環中出不來線程
加volatile 結果2code
aaa com in對象
aaa updata number value:60blog
main over60
加了volatile 線程aaa改了a的值,立馬刷新到主內存中去,並通知其它線程
當多個線程同時拿到值後,同時返回到主內存時,一個線程佔用了主內存,將值寫入,其它線程寫主內存,掛起,當通知其它線程時,其它線程就會寫進來,從而致使數據損失;
1 class Mydata{ 2 volatile int a=0; 3 public void resizeA() { 4 this.a++; 5 } 6 } 7 public class VolatileDemo { 8 public static void main(String[] args) { 9 Mydata mydata = new Mydata(); 10 for (int i = 0; i < 200; i++) { 11 for (int j = 0; j <100 ; j++) { 12 new Thread(()->{ 13 mydata.resizeA(); 14 },"aaa").start(); 15 } 16 } 17 while (Thread.activeCount() > 2) {//還剩2個,main和gc 18 Thread.yield();//讓出cpu 19 } 20 System.out.println(Thread.currentThread().getName()+"\t "+mydata.a); 21 } 22 23 }
計算的數值必定要大,很難發生數據損失
計算機爲了提升性能在執行程序是,編譯器和處理器會對程序執行指令重排;
單線程的狀況下不會改變最終的執行結果
必須考慮數據的依賴性
1 public class demo{ 2 int a=0; 3 boolean flag=false; 4 public void test(){ 5 a=1;//語句1 6 flag=true;//語句2 7 } 8 //由於沒有依賴關係,編譯器可能將1和2換位置 9 //多線程時,因爲速度太快,先執行2,1尚未執行,就執行了test2裏面的方法,致使結果沒法預測 10 public void test2(){ 11 if(flag){ 12 a+=5; 13 14 } 15 } 16 }
單例模式
1 public class demo{ 2 int a=0; 3 boolean flag=false; 4 public void test(){ 5 a=1;//語句1 6 flag=true;//語句2 7 } 8 //由於沒有依賴關係,編譯器可能將1和2換位置 9 //多線程時,因爲速度太快,先執行2,1尚未執行,就執行了test2裏面的方法,致使結果沒法預測 10 public void test2(){ 11 if(flag){ 12 a+=5; 13 14 } 15 } 16 }
synchronized不能禁止指令重排,因此要加volatile來禁止指令重排
由於實例化會發生三個步驟
1.分配內存空間
2.初始化對象
3.指向instance 此時!=null
由於2 3沒有數據依賴,因此可能發生指令重排,3先執行,2後,而此時2實際爲空對象,因此多線程,在3執行前,使用對象會發生異常;
拓展:不使用線程鎖來實現懶漢單例模式同時保證線程安全
1 //靜態內部類 2 public class Singleton4 { 3 private Singleton4(){} 4 private static class Inner{ 5 private static final Singleton4 INSTANCE=new Singleton4(); 6 } 7 public static Singleton4 getInstance(){ 8 return Inner.INSTANCE; 9 } 10 }