java-多線程深入(二)互斥性和可見性

(一)互斥性

互斥性,即原子性。原子,指最小的物質,具體不可再分性。

CPU運算中,對多線程進行時間片分割執行,一個程序塊執行時不可分割,即滿足互斥性原子性。

java中保證互斥性的方法:

1.用sychronized鎖住程序塊,實行互斥

synchronized (lock) {  
    a++;
}

2.用Atomic對變量操作實行互斥

public final static AtomicInteger TEST_INTEGER = new AtomicInteger(1);  
      
    public static void main(String []args) throws InterruptedException {  
        final Thread []threads = new Thread[20];  
         for(int i = 0 ; i < 20 ; i++) {  
             final int num = i;  
             threads[i] = new Thread() {  
                 public void run() { 
                    int now = TEST_INTEGER.incrementAndGet();  
                    System.out.println("我是線程:" + num + ",我得到值了,增加後的值爲:" + now);  
                 }  
             };  
             threads[i].start();  
         }  
         for(Thread t : threads) {  
             t.join();  
         }  
         System.out.println("最終運行結果:" + TEST_INTEGER.get());  
    }  
TEST_INTEGER在多線程操作中,最終結果不會出現偏差。

JDK的文檔中說:“設計原子類主要用作各種塊,用於實現非阻塞數據結構和相關基礎結構類。compareAndSet()方法不是鎖定的常規替換方法。僅當對象的重要更新限於單個變量時才應用它”。


(二)可見性

cpu和內存速度相差過高,引入緩存(cache、寄存器等);一個線程由線程id、指令計數器PC、寄存器集合和堆棧構成,詳見《程序員的自我修養》

每個線程有自己的工作內存,修改進程主內存的值,都需要拷貝到工作內存修改後,再回寫,其他線程可能出現,讀取到未回寫的髒數據這種情況。

/**
 * 多線程可見性測試
 * 
 * @author peter_wang
 * @create-time 2015-1-12 下午3:56:29
 */
public class ThreadVisableDemo {
    private static int a = 0;

    static class GetNumThread
        extends Thread {
        @Override
        public void run() {
            System.out.println(a);//B1
        }
    }

    static class ChangeNumThread
        extends Thread {
        @Override
        public void run() {
            a = 1;//A1,A2
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        GetNumThread getNumThread = new GetNumThread();
        ChangeNumThread changeNumThread = new ChangeNumThread();
        changeNumThread.start();//C1
        getNumThread.start();//C2
    }

}
執行結果:輸出0或者1


A1讀取完數據進行操作,寫入到線程A工作內存寫緩存中,不一定實時刷新主內存中a的值,B1可能讀取到舊數據。

java中保證可見性的方法:

1.用sychronized鎖住程序塊,實行互斥

static class GetNumThread
        extends Thread {
        @Override
        public void run() {
            synchronized (ThreadVisableDemo.class) {
                System.out.println(a);// B1
            }
        }
    }

    static class ChangeNumThread
        extends Thread {
        @Override
        public void run() {
            synchronized (ThreadVisableDemo.class) {
                a = 1;// A1,A2
            }
        }
    }
2.使用volatile,保證變量可見性

private static volatile int a = 0;
3.使用Atomic對變量操作,實現可見性


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章