java 併發操作之原子性與可視性

原子性

原子是世界上的最小單位,具有不可分割性。比如 a=0;(a非long和double類型) 這個操作是不可分割的,那麼我們說這個操作時原子操作。再比如:a++; 這個操作實際是a = a + 1;是可分割的,所以他不是一個原子操作。非原子操作都會存在線程安全問題,需要我們使用同步技術(sychronized)來讓它變成一個原子操作。一個操作是原子操作,那麼我們稱它具有原子性。java的concurrent包下提供了一些原子類,我們可以通過閱讀API來了解這些原子類的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。

可見性

可見性,是指線程之間的可見性,一個線程修改的狀態對另一個線程是可見的。也就是一個線程修改的結果。另一個線程馬上就能看到。比如:用volatile修飾的變量,就會具有可見性。volatile修飾的變量不允許線程內部緩存和重排序,即直接修改內存。所以對其他線程是可見的。但是這裏需要注意一個問題,volatile只能讓被他修飾內容具有可見性,但不能保證它具有原子性。比如 volatile int a = 0;之後有一個操作 a++;這個變量a具有可見性,但是a++ 依然是一個非原子操作,也就這這個操作同樣存在線程安全問題。

他們之間關係

原子性是說一個操作是否可分割。可見性是說操作結果其他線程是否可見。這麼看來他們其實沒有什麼關係。

實例

  1. package com.chu.test.thread;  
  2. /** 
  3.  * 可見性分析 
  4.  * @author Administrator 
  5.  * 
  6.  *volatile 會拒絕編譯器對其修飾的變量進行優化。也就不會存在重排序的問題。volatile只會影響可見性,不會影響原子性。 
  7.  *下面程序如果不加 
  8.  */  
  9. public class Test {  
  10.   
  11.     volatile int a = 1;  
  12.     volatile boolean ready;  
  13.       
  14.     public class PrintA extends Thread{  
  15.         @Override  
  16.         public void run() {  
  17.             while(!ready){  
  18.                 Thread.yield();  
  19.             }  
  20.             System.out.println(a);  
  21.         }  
  22.     }  
  23.     public static void main(String[] args) throws InterruptedException {  
  24.         Test t = new Test();  
  25.         t.new PrintA().start();  
  26.         //下面兩行如果不加volatile的話,執行的先後順序是不可預測的。並且下面兩行都是原子操作,但是這兩行作爲一個整體的話就不是一個原子操作。  
  27.         t.a = 48//這是一個原子操作,但是其結果不一定具有可見性。加上volatile後就具備了可見性。  
  28.         t.ready = true;//同理  
  29.     }  
  30.   
  31. }  


上面程序如果變量a不用volatile修飾那麼輸出結果很可能就是0.。

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