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

一文精通Java中的volatile關(guān)鍵字

 更新時間:2019年05月07日 09:39:14   作者:架構(gòu)與我  
volatile是java中的關(guān)鍵詞之一,這篇文章主要給大家介紹了關(guān)于Java中volatile關(guān)鍵字的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

前言

在一些開源的框架的源碼當中時不時都可以看到volatile這個關(guān)鍵字,最近特意學(xué)習(xí)一下volatile關(guān)鍵字的使用方法。

volatile 關(guān)鍵字:當多個線程進行操作共享數(shù)據(jù)時,可以保證內(nèi)存中的數(shù)據(jù)可見。 相較于 synchronized 是一種較為輕量級的同步策略。

缺點:

1. volatile 不具備“互斥性”

2. volatile 不能保證變量的“原子性”

很多資料中是這樣介紹volatile關(guān)鍵字的:

volatile是輕量級的synchronized,它在多處理器開發(fā)中保證了共享變量的“可見性”??梢娦缘囊馑际钱斠粋€線程修改一個共享變量時,另外一個線程能讀到這個修改的值。

文字不太好理解,通過例子來理解。

1、例子

首先看一個沒有使用volatile關(guān)鍵字例子:

package com.swnote.java;

/**
 * volatile測試例子
 *
 * @author lzj
 * @date [2019-04-47]
 */
public class VolatileTest {

 private boolean flag;

 public static void main(String[] args) {
 VolatileTest test = new VolatileTest();
 test.test();
 }

 public void test() {
 new Thread(() -> {
  try {
  Thread.sleep(1000L);
  } catch (InterruptedException e) {
  e.printStackTrace();
  }
  flag = true;
 }).start();

 new Thread(() -> {
  while (true) {
  if (flag) {
   System.out.println("thread flag = " + flag);
  }
  }
 }).start();
 }
}

該例子中定義了一個flag共享變量,test方法里面開啟了兩個線程,第一個線程在等待1秒中后修改共享變量flag的值為true,第二個線程通過循環(huán)判斷flag的值,當flag的值為true時,輸出內(nèi)容。

此時有兩種猜想:

  • 執(zhí)行后,可以看到輸出內(nèi)容,即說明第二個線程能夠感知到第一個線程對共享變量flag的修改
  • 執(zhí)行后,沒有任務(wù)內(nèi)容,即說明第二個線程無法感知到第一個線程對共享變量flag的修改

然后執(zhí)行結(jié)果為:

沒有任務(wù)的輸出內(nèi)容,即證明了此時這樣情況下第二個線程無法感知到第一個線程對共享變量flag的修改的

現(xiàn)在修改一下例子,即為flag變量加上volatile關(guān)鍵字,即:

private volatile boolean flag;

然后再運行,此時結(jié)果為:

此時就有內(nèi)容輸出了,說明加上volatile關(guān)鍵字后,第二個線程可以感知到第一個線程對共享變量flag的修改的,這就是上面概念中所說的volatile在多處理器開發(fā)中保證了共享變量的“可見性”。

2、原理

通過上面的例子證明了volatile在多處理器開發(fā)中保證了共享變量的“可見性”,那它是怎么實現(xiàn)的呢?

這時就得介紹一下Java的內(nèi)存模型了,首先看如下示意圖:

Java內(nèi)存模型是如上面所示的:

共享變量存儲在主內(nèi)存中,每個線程都有一個私有的本地內(nèi)存,本地內(nèi)存保存了被該線程使用到的主內(nèi)存的副本拷貝,線程對變量的所有操作都必須在自己的本地內(nèi)存中進行,而不能直接讀寫主內(nèi)存中的變量。

根據(jù)此理解,上述例子的在沒有加volatile時的情況是這樣的:

第一個線程從主內(nèi)存中獲取共享變量flag的值,此時值為false,將該值放到自己的本地內(nèi)存中,然后對變量進行修改,將值改為true,此時也只是將本地內(nèi)存中flag的值改為了true,此時還沒有將值同步到主內(nèi)存中,然后第二線程也是將共享變量flag的值放到自己的本地內(nèi)存中,而此時flag的值還是為false,所以就是一直沒有內(nèi)容輸出了。

然而加上volatile關(guān)鍵字后,第一個線程對flag的修改會強制刷新到主內(nèi)存中去,同時還會導(dǎo)致其他線程中的本地內(nèi)存的值會無效,需要重新到主內(nèi)存獲取,這樣就保證了第一個線程對flag修改后,第二線程能夠感知到。

3、注意點

volatile是輕量級的synchronized,但是它是不能夠代替synchronized的,因為volatile只能保證原子性操作的安全,對于復(fù)合操作,volatile是不能保證線程安全的。

例如:

package com.swnote.java;

/**
 * 復(fù)合操作例子
 *
 * @author lzj
 * @date [2019-04-27]
 */
public class StatisticTest {
 private volatile int num = 0;

 public static void main(String[] args) {
  StatisticTest test = new StatisticTest();
  test.statistic();
 }

 public void statistic() {
  for (int i = 0; i < 20; i++) {
   new Thread(() -> {
    num++;
   }).start();
  }

  System.out.println("num = " + num);
 }
}

期望的運行結(jié)果是20,可是幾乎每次運行結(jié)果都是不一樣的,例如有的結(jié)果為:

這是因為num++這個操作不是原子性的,所以即使使用了volatile關(guān)鍵字,也是不能保證安全的。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。

相關(guān)文章

  • RocketMq同組消費者如何自動設(shè)置InstanceName

    RocketMq同組消費者如何自動設(shè)置InstanceName

    這篇文章主要介紹了RocketMq同組消費者如何自動設(shè)置InstanceName問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • 詳解MyBatisPlus如何實現(xiàn)分頁和查詢操作

    詳解MyBatisPlus如何實現(xiàn)分頁和查詢操作

    這篇文章主要為大家詳細介紹了MyBatisPlus是如何實現(xiàn)分頁和查詢操作的,文中的示例代碼講解詳細,對我們學(xué)習(xí)有一定的幫助,需要的可以參考一下
    2022-05-05
  • SpringMVC入門實例

    SpringMVC入門實例

    這篇文章主要介紹了SpringMVC入門實例,在springmvc入門教程里算是比較不錯的,結(jié)構(gòu)也比較完整,需要的朋友可以參考。
    2017-11-11
  • Spring解決循環(huán)依賴問題及三級緩存的作用

    Spring解決循環(huán)依賴問題及三級緩存的作用

    這篇文章主要介紹了Spring解決循環(huán)依賴問題及三級緩存的作用,所謂的三級緩存只是三個可以當作是全局變量的Map,Spring的源碼中大量使用了這種先將數(shù)據(jù)放入容器中等使用結(jié)束再銷毀的代碼風格
    2022-07-07
  • springboot如何自定義pom內(nèi)子依賴版本

    springboot如何自定義pom內(nèi)子依賴版本

    這篇文章主要介紹了springboot如何自定義pom內(nèi)子依賴版本問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 關(guān)于Spring Boot動態(tài)權(quán)限變更問題的實現(xiàn)方案

    關(guān)于Spring Boot動態(tài)權(quán)限變更問題的實現(xiàn)方案

    這篇文章主要介紹了Spring Boot動態(tài)權(quán)限變更實現(xiàn)的整體方案使用session作為緩存,結(jié)合AOP技術(shù)進行token認證和權(quán)限控制,本文給大家介紹的非常詳細,需要的朋友參考下吧
    2021-06-06
  • 基于Java匯總Spock框架Mock靜態(tài)資源經(jīng)驗

    基于Java匯總Spock框架Mock靜態(tài)資源經(jīng)驗

    這篇文章主要介紹了基于Java匯總Spock框架Mock靜態(tài)資源經(jīng)驗,前面講了?Spock框架Mock對象、方法經(jīng)驗總結(jié),今天分享一下Spock框架中Mock靜態(tài)資源的實踐經(jīng)驗匯總。分成靜態(tài)資源和混合場景,需要的朋友可以參考一下
    2022-02-02
  • idea中的jvm調(diào)優(yōu)方式

    idea中的jvm調(diào)優(yōu)方式

    這篇文章主要介紹了idea中的jvm調(diào)優(yōu)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Java微信公眾平臺開發(fā)(6) 微信開發(fā)中的token獲取

    Java微信公眾平臺開發(fā)(6) 微信開發(fā)中的token獲取

    這篇文章主要為大家詳細介紹了Java微信公眾平臺開發(fā)第六步,微信開發(fā)中的token獲取,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • SpringBoot Jpa 自定義查詢實現(xiàn)代碼詳解

    SpringBoot Jpa 自定義查詢實現(xiàn)代碼詳解

    這篇文章主要介紹了SpringBoot Jpa 自定義查詢實現(xiàn)代碼詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02

最新評論

岱山县| 资阳市| 汶上县| 玛纳斯县| 那坡县| 来宾市| 邓州市| 湄潭县| 马尔康县| 内乡县| 南汇区| 灌云县| 余姚市| 同仁县| 中西区| 麦盖提县| 佳木斯市| 伊春市| 镇康县| 金寨县| 栾川县| 克东县| 定边县| 佛坪县| 株洲县| 烟台市| 乌苏市| 平阳县| 洪雅县| 土默特左旗| 辽宁省| 岳阳市| 临洮县| 上饶市| 梁平县| 盐池县| 郧西县| 剑阁县| 托里县| 吴桥县| 桦川县|