最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文讀懂a(chǎn)va中的Volatile關(guān)鍵字使用

 更新時間:2020年03月07日 10:32:22   作者:flydean  
volatile關(guān)鍵字的作用保證了變量的可見性(visibility)。被volatile關(guān)鍵字修飾的變量,如果值發(fā)生了變更,其他線程立馬可見,避免出現(xiàn)臟讀的現(xiàn)象。這篇文章主要介紹了ava中的Volatile關(guān)鍵字使用,需要的朋友可以參考下

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

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

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

什么時候使用volatile

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

public class VolatileWithoutUsage {
 private int count = 0;

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

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

@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() );
 }

運行一下,我們會發(fā)現(xiàn)結(jié)果是不等于1000的。

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

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

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

public class VolatileFalseUsage {
 private volatile int count = 0;

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

}

上面的類中,我們加上了關(guān)鍵字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() );
 }

運行一下,我們會發(fā)現(xiàn)結(jié)果還是錯誤的:

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

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

下面看下正確的用法:

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 是指當(dāng)volatile進(jìn)行寫回主內(nèi)存的操作時,會將之前的非volatile的操作一并寫回主內(nèi)存。

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 將會表現(xiàn)的和volatile一樣。

本文的例子可以參考

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

總結(jié)

到此這篇關(guān)于一文讀懂a(chǎn)va中的Volatile關(guān)鍵字使用的文章就介紹到這了,更多相關(guān)java volatile關(guān)鍵字內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java基礎(chǔ)之教你如何正確運用依賴注入

    Java基礎(chǔ)之教你如何正確運用依賴注入

    最近發(fā)現(xiàn)很多使用Spring框架的Java代碼存在依賴注入方式的誤用,甚至是濫用.因此整理了這篇文章,歡迎大家一起探討,需要的朋友可以參考下
    2021-05-05
  • Java基于Tcp的基礎(chǔ)聊天功能實例

    Java基于Tcp的基礎(chǔ)聊天功能實例

    這篇文章主要介紹了Java基于Tcp的基礎(chǔ)聊天功能,結(jié)合實例形式分析了java基于tcp協(xié)議的數(shù)據(jù)傳輸實現(xiàn)聊天功能相關(guān)操作技巧,需要的朋友可以參考下
    2020-01-01
  • java、freemarker保留兩位小數(shù)

    java、freemarker保留兩位小數(shù)

    這篇文章主要介紹了 java、freemarker保留兩位小數(shù)的實現(xiàn)方法,然后給大家補充介紹了freemarker保留兩位小數(shù)的詳解,需要的朋友可以參考下
    2017-03-03
  • 利用Sharding-Jdbc組件實現(xiàn)分表

    利用Sharding-Jdbc組件實現(xiàn)分表

    這篇文章主要為大家詳細(xì)介紹了利用Sharding-Jdbc組件實現(xiàn)分表,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • SpringSecurity實現(xiàn)踢出指定用戶的示例

    SpringSecurity實現(xiàn)踢出指定用戶的示例

    SpringSecurity中使用SessionRegistryImpl類可以獲取session信息并踢出用戶,這篇文章主要介紹了SpringSecurity實現(xiàn)踢出指定用戶的示例,需要的朋友可以參考下
    2025-03-03
  • Java新手環(huán)境搭建 JDK8安裝配置教程

    Java新手環(huán)境搭建 JDK8安裝配置教程

    這篇文章主要為大家詳細(xì)介紹了Java新手環(huán)境搭建,JDK8安裝配置教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • 使用JWT作為Spring?Security?OAuth2的token存儲問題

    使用JWT作為Spring?Security?OAuth2的token存儲問題

    這篇文章主要介紹了使用JWT作為Spring?Security?OAuth2的token存儲,大家經(jīng)常使用的方法有兩種一種是使用JWT作為Token傳遞,一種是使用Redis存儲Token,資源服務(wù)器本地訪問Redis校驗Token,需要的朋友可以參考下
    2021-12-12
  • Java Collections.sort()排序代碼案例

    Java Collections.sort()排序代碼案例

    這篇文章主要介紹了Java Collections.sort()排序代碼案例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • SpringBoot3+graalvm:整合并打包為可執(zhí)行文件方式

    SpringBoot3+graalvm:整合并打包為可執(zhí)行文件方式

    本文介紹了如何在Spring Boot 3中整合GraalVM,并將其打包為可執(zhí)行文件,適用于Windows和Linux系統(tǒng),通過安裝GraalVM、配置環(huán)境變量、下載Visual Studio組件(僅限Windows)以及使用Maven容器(適用于Linux),可以實現(xiàn)高效的打包和運行
    2024-12-12
  • Java?Zip壓縮之簡化文件和文件夾的壓縮操作

    Java?Zip壓縮之簡化文件和文件夾的壓縮操作

    這篇文章主要給大家介紹了關(guān)于Java?Zip壓縮之簡化文件和文件夾的壓縮操作,Zip壓縮是一種常見的文件壓縮格式,它將多個文件和文件夾打包成一個以.zip為后綴的壓縮包,需要的朋友可以參考下
    2023-10-10

最新評論

浪卡子县| 同心县| 保靖县| 云和县| 浦江县| 依兰县| 襄垣县| 波密县| 宝鸡市| 铜山县| 抚宁县| 中超| 平湖市| 新和县| 新和县| 胶南市| 松溪县| 什邡市| 松溪县| 武城县| 洪湖市| 叶城县| 晋城| 兰溪市| 涞水县| 青铜峡市| 额尔古纳市| 阿城市| 镇雄县| 滨海县| 安陆市| 无为县| 洪洞县| 彩票| 花莲县| 石屏县| 绵阳市| 阿坝| 镇坪县| 海宁市| 闻喜县|