1. 程式人生 > >java多線程---volatile

java多線程---volatile

rgs 不同 void 出現 寫到 程序 sys 運行時 inter

被volatile修飾的變量能夠保證每個線程能夠獲取該變量的最新值,從而避免出現數據臟讀的現象。
當把變量聲明為volatile類型後,編譯器與運行時都會註意到這個變量是共享的,因此不會將該變量上的操作與其他內存操作一起重排序。volatile變量不會被緩存在寄存器或者對其他處理器不可見的地方,因此在讀取volatile類型的變量時總會返回最新寫入的值。在訪問volatile變量時不會執行加鎖操作,因此也就不會使執行線程阻塞,因此volatile變量是一種比sychronized關鍵字更輕量級的同步機制。

  • 1.非volatile變量,讀寫時,每個線程從內存copy到cpu緩存中,多核cpu,每個線程在不同的cpu上被處理。變量會被copy到不同的cpu緩存中
  • 2.volatile變量,每次從內存中讀,跳過了cpu緩存這一步。

  • 特性
    1.可見性。可見性是指當多個線程訪問同一個變量時,一個線程修改了這個變量的值,其他線程能夠立即看得到修改的值。
    2.有序性。禁止指令重排序優化。

eg

public class VolatileTest {
    
    public static volatile int  i = 0 ;
    
    public static class VTTest implements Runnable{
            @Override
            public void run() {
                for
(int j = 0; j < 1000; j++) { i++; //可以理解為3步,1:讀到工作內存,2:進行+1計算 3:寫入新的i+1 System.out.println(Thread.currentThread().getId() + ":" + i); } } } public static void main(String[] args) throws InterruptedException { Thread[] t = new
Thread[10]; for (int i = 0; i < 10; i++) { t[i] = new Thread(new VTTest()); t[i].start(); } for (int i = 0; i < 10; i++) { t[i].join(); } } }
由於volatile保證了可見性,那麽在每個線程中對i自增完之後,在其他線程中都能看到修改後的值啊,所以有10個線程分別進行了1000次操作,那麽最終i的值應該是1000*10=10000。這裏面就有一個誤區了,volatile關鍵字能保證可見性沒有錯,但是上面的程序錯在沒能保證原子性。可見性只能保證每次讀取的是最新的值,但是volatile沒辦法保證對變量的操作的原子性。比如現在有2個線程,線程1開始讀取i到工作內存,進行+1操作,在線程1還沒有進行寫操作,線程2也開始讀取i到工作內存,進行+1操作,由於線程1還沒有寫操作,所以線程2的i還是有效的,線程1將遞增的結果寫到主內存,線程2讀取到工作內存中的i無效,但是線程2已經對i遞增完,也開始對i進行寫入到主內存操作,所以最終2個線程最終只對i進行一次遞增操作。那麽怎麽保證原子性呢,答案是加鎖。

eg

public class VolatileTest {
    
    public static volatile int  i = 0 ;
    
    public static ReentrantLock lock = new ReentrantLock();  
    
    public static class VTTest implements Runnable{
            @Override
            public void run() {
                for (int j = 0; j < 1000; j++) {
                    lock.lock();
                    i++;    //i = i + 1;非原子操作
                    System.out.println(Thread.currentThread().getId() + ":" + i);
                    lock.unlock();
                }
            }
    }
    
    public static void main(String[] args) throws InterruptedException {
        Thread[] t = new Thread[10];
        for (int i = 0; i < 10; i++) {
            t[i] = new Thread(new VTTest());
            t[i].start();
        }
        for (int i = 0; i < 10; i++) {
            t[i].join();
        }
    }
}

java多線程---volatile