線程安全問題與volatile字段

線程安全問題

/**
 * 出現有些沒加入list的緣由:線程一拿走了這個list當時裏面有10個數據,添加一個變成11個
 * 線程二同時拿走了這個list,當時裏面有10個數據,添加一個變成11個(可是正常應該是12個,也就是線程1添加的那個數據沒有了)
 */
public class Ticket implements Runnable{
    
    private List<String> list = new ArrayList<>();

    public void run(){
        for(int i=0;i<300;i++){
            try {
                // 調用Thread類的sleep方法,休眠50ms,因爲父接口沒有throws異常,so咱們只能用try...catch
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            list.add("xxx,");
            System.out.println(list.size());
        }
    }

}

結論:多線程操做同一個全局變量,加上線程鎖吧java

volatile字段

volatile字段的做用:往常線程都是將某個變量複製一份到本身的線程中,通過volatile字段修飾後,就統一的從內存中讀取安全

原理:volatile本質是在告訴jvm當前變量在寄存器(工做內存)中的值是不肯定的,須要從主存中讀取;多線程

Volatile 變量具備 synchronized 的可見性特性,可是不具有原子性。這就是說線程可以自動發現 volatile 變量的最新值。jvm

  •  volatile 變量不能用做線程安全計數器。雖然增量操做(x++)看上去相似一個單獨操做,實際上它是一個由(讀取-修改-寫入)操做序列組成的組合操做,必須以原子方式執行,而 volatile 不能提供必須的原子特性。

用處:若是讀操做遠遠大於寫操做,volatile 變量還能夠提供優於鎖的性能優點。性能

兩個字段的區別

  1. volatile本質是在告訴jvm當前變量在寄存器(工做內存)中的值是不肯定的,須要從主存中讀取; synchronized則是鎖定當前變量,只有當前線程能夠訪問該變量,其餘線程被阻塞住
  2. volatile僅能使用在變量級別;synchronized則可使用在變量、方法、和類級別的
  3. volatile僅能實現變量的修改可見性,不能保證原子性;而synchronized則能夠保證變量的修改可見性和原子性
  4. volatile不會形成線程的阻塞;synchronized可能會形成線程的阻塞。
  5. volatile標記的變量不會被編譯器優化;synchronized標記的變量能夠被編譯器優化
相關文章
相關標籤/搜索