volatile的做用是使變量在多個線程間可見安全
1.死循環服務器
public class PrintInfo implements Runnable { private boolean statu = true; public boolean isStatu() { return statu; } public void setStatu(boolean statu) { this.statu = statu; } public void printInfo() { try { while(statu == true){ System.out.println("The Thread Name Is " + Thread.currentThread().getName()); Thread.sleep(1000); Thread.sleep(1000); } } catch (Exception e) { e.printStackTrace(); } } @Override public void run() { printInfo(); } }
public class Run { public static void main(String[] args){
PrintInfo printInfo = new PrintInfo(); printInfo.printInfo(); System.out.println("Try To Stop The Thread"); printInfo.setStatu(false);
}
}多線程
運行結果:異步
2.解決同步死循環ide
將一中的代碼Run類修改成性能
public class Run { public static void main(String[] args) throws InterruptedException { PrintInfo printInfo = new PrintInfo(); Thread thread = new Thread(printInfo); thread.start(); Thread.sleep(1000); System.out.println("Try To Stop The Thread"); printInfo.setStatu(false); } }
運行結果:this
但當上面的實例代碼運行在 -server服務器模式的64位的JVM上時,會出現死循環,解決的辦法是使用volatile關鍵字.線程
volatile關鍵字的做用是強制從公共堆棧中取得變量的值,而不是從線程使用數據棧中取得變量的值server
3.解決異步死循環內存
將1中的代碼PrintInfo修改成
public class PrintInfo implements Runnable { volatile private boolean statu = true; public boolean isStatu() { return statu; } public void setStatu(boolean statu) { this.statu = statu; } public void printInfo() { try { while(statu == true){ System.out.println("The Thread Name Is " + Thread.currentThread().getName()); Thread.sleep(1000); } } catch (Exception e) { e.printStackTrace(); } } @Override public void run() { printInfo(); } }
運行結果:
4.關鍵字synchronized與volatile的區別
使用volatile關鍵字增長了實例變量在多個線程之間的可見性,可是volatile關鍵字的缺點是不支持原子性.
1).關鍵字volatile是線程同步的輕量級實現,因此volatile性能確定比synchronized要好,而且volatile只能修飾於變量,二synchronized能夠修飾方法,以及代碼塊.隨着JDK新版本的發佈,synchronized關鍵字的執行效率獲得很大提高,在開發中使用synchronized關鍵字的比例仍是比較大.
2).多線程訪問volatile不會發生阻塞,二synchronized回出現阻塞
3).volatile能保證數據的可見性.但不能保證原子性,而synchronized能夠保證原子性,也能夠間接保證可見性,之內他會將使用內存和公共內存中的數據作同步.
4).關鍵字volatile解決的是變量在多個線程之間的可見性,而synchronized關鍵字解決的是多個線程之間訪問資源的同步性,
線程安全包含原子性和可見性兩個方面,JAVA的同步機制都是圍繞這兩個方面來確保線程安全的.
5.volatile的非原子特性
public class VolatileThread extends Thread{ volatile public static int count ; private static void sumCount(){ for(int i = 0 ; i < 10 ; i ++){ count ++; } System.out.println("count = " + count); } @Override public void run() { sumCount(); } }
public class Run { public static void main(String[] args){ VolatileThread[] volatileThreads = new VolatileThread[100]; for(int i = 0 ; i < 10 ; i ++){ volatileThreads[i] = new VolatileThread(); } for(int i = 0 ; i < 10 ; i ++){ volatileThreads[i].start(); } } }
運行結果:
更改VolatileThread類代碼爲:
public class VolatileThread extends Thread{ volatile public static int count ; synchronized private static void sumCount(){ for(int i = 0 ; i < 10 ; i ++){ count ++; } System.out.println("count = " + count); } @Override public void run() { sumCount(); } }
運行結果:
關鍵字volatile主要使用的場合是在多個線程中能夠感知實例變量被更改了,而且能夠得到最新的值使用,也就是用多線程讀取共享變量時能夠獲取最新值使用.
關鍵字volatile提示線程每次從共享內存中讀取變量,而不是從私有內存中讀取,這樣就保證了同步數據的可見性,但須要注意的是:若是修改實例變量中的數據,好比i++,這樣的操做其實並非一個院子操做,也就是非線程安全的.
表達式i++的操做不走分解以下:
1).從內存中獲取i的值,
2).計算i的值,
3).將計算後的值存儲到內存中.
若是在第二步時,另外一個線程也修改了i的值,那麼這個時候就會出現髒數據,解決的辦法就是使用synchronized關鍵字,因此volatile自己並不處理數據的原子性,而是強制對數據的讀寫及時影響到主內存.