溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中Volatile怎么用

發(fā)布時間:2021-08-25 14:58:44 來源:億速云 閱讀:136 作者:小新 欄目:編程語言

這篇文章將為大家詳細講解有關Java中Volatile怎么用,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

 Volatile:

volatile同步機制又涉及Java內存模型中的可見性、原子性和有序性,惡補基礎一波。

可見性:

可見性簡單的說是線程之間的可見性,一個線程修改的狀態(tài)對另一個線程是可見對,也就是一個線程的修改結果另一個線程可以馬上看到;但通常,我們無法確保執(zhí)行讀操作的線程能夠時時的看到其他線程寫入的值,So為了確保多個線程之間對內存寫入操作可見性,必須使用同步機制;如用volatile修飾的變量就具有可見性,volatile修飾的變量不允許線程內部緩存和重排序,而是直接修改內存,所以對其他線程來說是可見的;但volatile只能保證被修飾的內容具有可見性,并不具備原子性,如volatile int vipNumber = 100,之后有一個vipNumber++ 的操作,這個變量vipNumber具有可見性,但是vipNumber++ 依然是一個非原子操作,也就是說這個操作同樣存在線程安全問題。

原子性:

原子具有不可分割的特性,如int age = 22,這個操作是不可分割的,那么稱其為原子操作,具有原子性;再比如age++,這個操作實際是age = age + 1,其是可分割的,So它不是一個原子操作;而非原子操作都會存在線程安全問題,需要我們使用同步技術(synchronized)來讓它變成一個原子操作;Java的concurrent包下提供了一些原子類,如:AtomicLongMap、AtomicDouble、AtomicReference 等;在Java中用synchronized、lock和unlock來保證原子性。

有序性:

Java語言提供了volatile和synchronized兩個關鍵字來保證線程之間操作的有序性,volatile是因為本身包含“禁止指令重排序”的語義,synchronized是由“一個變量在同一時刻只允許一條線程對其進行l(wèi)ock操作”這條規(guī)則獲得有序性的,此規(guī)則決定了持有同一個對象鎖的兩個同步塊只能串行執(zhí)行。

Volatile原理:

volatile是一種稍弱的同步機制,其用來確保將變量的更新操作通知到其他線程;當變量聲明為volatile類型后,編譯器與JVM運行時都會注意到這個變量時共享的,因此不會將此變量上的操作與其他操作一起重排序;volatile修飾后變量不會緩存在寄存器或者對其他處理器不可見的地方,因此在單曲volatile類型的變量時總會返回最新寫入的值;除此之外,在訪問volatile變量時不會執(zhí)行加鎖操作,也就不會執(zhí)行線程阻塞,因此volatile變量是一種比synchronized關鍵字更輕量級的同步機制;當對非volatile變量進行讀寫時,每個線程從內存拷貝變量到CPU緩存中,如果計算機有多個CPU則每個線程可能在不同的CPU上被處理,這就意味著每個線程都可以拷貝到不同的CPU緩存cache中,而不是像volatile變量那樣直接讀內存,JVM保證其每次讀變量都從內存中讀,跳過了CPU cache這一步驟。

當一個變量定義為volatile之后,其具備的兩種特征:

1、保證此變量對所有的線程的可見性;當一個線程修改了此變量的值,volatle保證新值能夠立即同步到主內存,以及每次使用前立即從主每次刷新;

2、禁止指令重排序優(yōu)化;被volatile修飾的變量賦值后多執(zhí)行了一個“l(fā)oad”操作,此操作相當于一個內存屏障(指令重排序時不能把后面的指令重排序到內存屏障之前到位置),只有一個CPU訪問內存時,不需要內存屏障;(指令重排序:指CPU采用了允許將多條指令不按程序規(guī)定的順序分開發(fā)送給各相應電路單元處理)

另外:在性能方面,volatile的讀操作性能消耗與普通變量基本無異,但是寫操作稍慢,因為它需要在本地代碼中插入許多內存屏障來保證處理器不發(fā)生亂序執(zhí)行。

這里擼了一個例子用volatile保證線程間的同步,如果變量author不經volatile修飾,線程2中對author的值做了修改并未同步到線程1中,其一直存在緩存中。

Java中Volatile怎么用

FYI:

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TestVolatile {
 //private volatile String author = "tjt"; // volatile修飾author保證兩個線程到可見性,即不存在緩存cache中
 private String author = "tjt"; // 不用volatile修飾變量author則author修改值后在線程之間并不可見
 private boolean enable = false;
 public static void main(String[] args) throws Exception {
  TestVolatile testVolatile = new TestVolatile();
  log.info("原始定義的author: "+testVolatile.author);
  Thread thread = new Thread( new Runnable() {
   @Override
   public void run() {
    testVolatile.testMethodOne();
   }
  });
  thread.start();
  thread.sleep(2000l);
  testVolatile.testMethodTwo();
 }
 public void testMethodOne() {
  while(true) {
   if ("detect_tjt".equals(author) && enable == false) {
    log.info("線程testMethodOne中檢測到來author修改為: "+author);
    enable = true;
    System.exit(0);
   }
  }  }
 public void testMethodTwo() {
  author = "detect_tjt";
  log.info("線程testMethodTwo中把author修改為: "+author);
 }
}

用volatile修飾author執(zhí)行結果:
- 原始定義的author: tjt
- 線程testMethodTwo中把author修改為: detect_tjt
- 線程testMethodOne中檢測到來author修改為: detect_tjt
無volatile修飾author執(zhí)行結果:

- 原始定義的author: tjt
- 線程testMethodTwo中把author修改為: detect_tjt

關于“Java中Volatile怎么用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI