多線程學習筆記(十二)

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自己並不處理數據的原子性,而是強制對數據的讀寫及時影響到主內存.

相關文章
相關標籤/搜索