中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

一文讀懂ava中的Volatile關鍵字使用

發布時間:2020-08-30 18:42:16 來源:腳本之家 閱讀:162 作者:flydean 欄目:編程語言

在本文中,我們會介紹java中的一個關鍵字volatile。 volatile的中文意思是易揮發的,不穩定的。那么在java中使用是什么意思呢?

我們知道,在java中,每個線程都會有個自己的內存空間,我們稱之為working memory。這個空間會緩存一些變量的信息,從而提升程序的性能。當執行完某個操作之后,thread會將更新后的變量更新到主緩存中,以供其他線程讀寫。

因為變量存在working memory和main memory兩個地方,那么就有可能出現不一致的情況。 那么我們就可以使用Volatile關鍵字來強制將變量直接寫到main memory,從而保證了不同線程讀寫到的是同一個變量。

什么時候使用volatile

那么我們什么時候使用volatile呢?當一個線程需要立刻讀取到另外一個線程修改的變量值的時候,我們就可以使用volatile。我們來舉個例子:

public class VolatileWithoutUsage {
 private int count = 0;

 public void incrementCount() {
 count++;
 }
 public int getCount() {
 return count;
 }
}

這個類定義了一個incrementCount()方法,會去更新count值,我們接下來在多線程環境中去測試這個方法:

@Test
 public void testWithoutVolatile() throws InterruptedException {
 ExecutorService service= Executors.newFixedThreadPool(3);
 VolatileWithoutUsage volatileWithoutUsage=new VolatileWithoutUsage();

 IntStream.range(0,1000).forEach(count ->service.submit(volatileWithoutUsage::incrementCount) );
 service.shutdown();
 service.awaitTermination(1000, TimeUnit.MILLISECONDS);
 assertEquals(1000,volatileWithoutUsage.getCount() );
 }

運行一下,我們會發現結果是不等于1000的。

java.lang.AssertionError:
Expected :1000
Actual   :999

這是因為多線程去更新同一個變量,我們在上篇文章也提到了,這種情況可以通過加Synchronized關鍵字來解決。

那么是不是我們加上Volatile關鍵字后就可以解決這個問題了呢?

public class VolatileFalseUsage {
 private volatile int count = 0;

 public void incrementCount() {
 count++;
 }
 public int getCount() {
 return count;
 }

}

上面的類中,我們加上了關鍵字Volatile,我們再測試一下:

@Test
 public void testWithVolatileFalseUsage() throws InterruptedException {
 ExecutorService service= Executors.newFixedThreadPool(3);
 VolatileFalseUsage volatileFalseUsage=new VolatileFalseUsage();

 IntStream.range(0,1000).forEach(count ->service.submit(volatileFalseUsage::incrementCount) );
 service.shutdown();
 service.awaitTermination(5000, TimeUnit.MILLISECONDS);
 assertEquals(1000,volatileFalseUsage.getCount() );
 }

運行一下,我們會發現結果還是錯誤的:

java.lang.AssertionError:
Expected :1000
Actual   :992
~~

為什么呢? 我們先來看下count++的操作,count++可以分解為三步操作,1. 讀取count的值,2.給count加1, 3.將count寫回內存。添加Volatile關鍵詞只能夠保證count的變化立馬可見,而不能保證1,2,3這三個步驟的總體原子性。 要實現總體的原子性還是需要用到類似Synchronized的關鍵字。

下面看下正確的用法:

public class VolatileTrueUsage {

private volatile int count = 0;

public void setCount(int number) {
 count=number;
}
public int getCount() {
 return count;
}
}

@Test
public void testWithVolatileTrueUsage() throws InterruptedException {
 VolatileTrueUsage volatileTrueUsage=new VolatileTrueUsage();
 Thread threadA = new Thread(()->volatileTrueUsage.setCount(10));
 threadA.start();
 Thread.sleep(100);

 Thread reader = new Thread(() -> {
 int valueReadByThread = volatileTrueUsage.getCount();
 assertEquals(10, valueReadByThread);
 });
 reader.start();
}
## Happens-Before 

從java5之后,volatile提供了一個Happens-Before的功能。Happens-Before 是指當volatile進行寫回主內存的操作時,會將之前的非volatile的操作一并寫回主內存。

public class VolatileHappenBeforeUsage {

int a = 0;
volatile boolean flag = false;

public void writer() {
 a = 1;  // 1 線程A修改共享變量
 flag = true; // 2 線程A寫volatile變量
}
}

上面的例子中,a是一個非volatile變量,flag是一個volatile變量,但是由于happens-before的特性,a 將會表現的和volatile一樣。

本文的例子可以參考

[https://github.com/ddean2009/learn-java-concurrency/tree/master/volatile](https://github.com/ddean2009/learn-java-concurrency/tree/master/volatile)

總結

到此這篇關于一文讀懂ava中的Volatile關鍵字使用的文章就介紹到這了,更多相關java volatile關鍵字內容請搜索億速云以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持億速云!

向AI問一下細節

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

AI

黔西县| 舞阳县| 宁陵县| 资兴市| 江安县| 金乡县| 阜阳市| 昌平区| 南部县| 金秀| 丰县| 榕江县| 华池县| 开鲁县| 平原县| 衡阳市| 乡城县| 沐川县| 抚松县| 建德市| 晋中市| 康平县| 虎林市| 含山县| 五原县| 和田县| 洛川县| 龙山县| 新昌县| 离岛区| 宜章县| 睢宁县| 华坪县| 通辽市| 永州市| 林甸县| 龙胜| 淮安市| 贡嘎县| 瑞金市| 合作市|