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

Java中多線程與并發(fā)_volatile關鍵字的深入理解

 更新時間:2020年12月14日 10:47:38   作者:shuPush  
這篇文章主要給大家介紹了關于Java中多線程與并發(fā)_volatile關鍵字的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

一、volatile關鍵字

volatile是JVM提供的一種輕量級的同步機制,特性:

1.保證內存可見性

2.不保證原子性

3.防止指令重排序

二、JMM(Java Memory Model)

Java內存模型中規(guī)定了所有的變量都存儲在主內存中(如虛擬機物理內存中的一部分),每條線程還有自己的工作內存(如CPU中的高速緩存),線程的工作內存中保存了該線程使用到的變量到主內存的副本拷貝,線程對變量的所有操作(讀取、賦值)都必須在工作內存中進行,而不能直接讀寫主內存中的變量。不同線程之間無法直接訪問對方工作內存中的變量,線程間變量值的傳遞均需要通過主內存來完成,線程、主內存和工作內存的交互關系如下圖所示:

三、驗證

1.驗證volatile的可見性

1.1 假如 int num = 0; num變量之前根本沒有添加volatile關鍵字修飾,沒有可見性

1.2 添加了volatile,可以解決可見性問題

MyData類

class MyData {
 volatile int num = 0;

 public void addT060() {
 this.num = 60;
 }
}

內存可見性驗證,其中兩個線程分別為AAA線程和main線程

 //volatile可以保證可見性,及時通知其它線程,主內存的值已經被修改
 @Test
 public void seeOkByVolatile() {
 MyData myData = new MyData();//資源類

 new Thread(() -> {
  System.out.println(Thread.currentThread().getName() + "\t come in");
  //暫停一會線程
  try{
  TimeUnit.SECONDS.sleep(3);
  }catch (InterruptedException e) {
  e.printStackTrace();
  }
  myData.addT060();
  System.out.println(Thread.currentThread().getName() + "\t update num value: " + myData.num);
 },"AAA").start();

 //第2個線程是我們的main線程
 while (myData.num == 0) {
  //main線程就一直在這里等待循環(huán),直到num值不再等于0.
 }
 System.out.println(Thread.currentThread().getName() + "\t mission is over,main get num value: " + myData.num );
 }

對num變量加volatile修飾后結果

AAA come in
AAA update num value: 60
main 我能見到AAA線程對num修改的結果啦,main get num value: 60

Process finished with exit code 0

2.驗證volatile不保證原子性

2.1 原子性指的是什么意思?

不可分割,完整性,也即某個線程正在做某個具體任務時,中間不可以被加塞或者被分割。需要整體完整。要么同時成功,要么同時失敗。

2.2 volatile不保證原子性的案例演示

2.3 為什么不保證原子性?

2.4 如何保證原子性

加sync

使用我們juc下的AtomicInteger (底層實現(xiàn)CAS)

給MyData類加addPlusPlus()方法

class MyData {//MyData.java ===> MyData.class ===> JVM字節(jié)碼
 int num = 0;

 public void addT060() {
 this.num = 60;
 }

 //請注意,此時num前面是加了關鍵字修飾的,volatile不保證原子性
 public void addPlusPlus() {
 num++;
 }
}

2.2 volatile不保證原子性的案例演示

num++在多線程操作的情況下不保證原子性的

創(chuàng)建20個線程并行執(zhí)行num++操作2000次,多次測試,結果不為40000

public static void main(String[] args) {
 MyData myData = new MyData();

 for (int i = 1; i <= 20; i++ ) {

  new Thread(() -> {
  for (int j = 1; j <= 2000; j++) {
   myData.addPlusPlus();
  }

  },String.valueOf(i)).start();
 }

 //需要等待上面20個線程都全部計算完成后,再用main線程取得最終的結果值看是多少?
 while(Thread.activeCount() > 2) {
  Thread.yield();
 }

 System.out.println(Thread.currentThread().getName() + "\t finally num value:" + myData.num);
 }

結果:數(shù)值小于40000,出現(xiàn)寫值丟失的情況

main  finally num value:38480

Process finished with exit code 0

2.3 為什么不保證原子性?

因為當線程A對num++操作從自己的工作內存刷新到主內存時,還未通知到其他線程主內存變量有更新的瞬間,其他線程對num變量的操作結果也對主內存進行了刷新,從而導致了寫值丟失的情況

num++通過匯編指令分析,通過javap反編譯得到如下匯編指令

class com.slx.juc.MyData {
 volatile int num;

 com.slx.juc.MyData();
 Code:
 0: aload_0
 1: invokespecial #1   // Method java/lang/Object."<init>":()V
 4: aload_0
 5: iconst_0
 6: putfield #2   // Field num:I
 9: return

 public void addT060();
 Code:
 0: aload_0
 1: bipush 60
 3: putfield #2   // Field num:I
 6: return

 public void addPlusPlus();
 Code:
 0: aload_0
 1: dup
 2: getfield #2   // Field num:I
 5: iconst_1
 6: iadd
 7: putfield #2   // Field num:I
 10: return
}

可見num++被拆分成了3個步驟,簡稱:讀-改-寫

  • 執(zhí)行getfield拿到原始num;
  • 執(zhí)行iadd進行加1操作;
  • 執(zhí)行putfield寫把累加后的值寫回

2.4 如何保證原子性

加sync

使用我們juc下的AtomicInteger (底層實現(xiàn)CAS)

MyData類中添加原子類操作方法

 AtomicInteger atomicInteger = new AtomicInteger();
 public void addMyAtomic() {
 atomicInteger.getAndIncrement();
 }

調用該方法打印結果

 public static void main(String[] args) {
 MyData myData = new MyData();

 for (int i = 1; i <= 20; i++ ) {

  new Thread(() -> {
  for (int j = 1; j <= 2000; j++) {
   myData.addMyAtomic();
  }

  },String.valueOf(i)).start();
 }

 //需要等待上面20個線程都全部計算完成后,再用main線程取得最終的結果值看是多少?
 while(Thread.activeCount() > 2) {
  Thread.yield();
 }

 System.out.println(Thread.currentThread().getName() + "\t AtomicInteger type ,finally num value:" + myData.atomicInteger);
 }

測試結果為40000,不會出現(xiàn)之前int類型的丟失值的情況

main  AtomicInteger type ,finally num value:40000

Process finished with exit code 0

總結

到此這篇關于Java中多線程與并發(fā)_volatile關鍵字的文章就介紹到這了,更多相關Java多線程與并發(fā)_volatile關鍵字內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java LRU算法介紹與用法示例

    java LRU算法介紹與用法示例

    這篇文章主要介紹了java LRU算法,簡單介紹了LRU算法的概念并結合實例形式分析了LRU算法的具體使用方法,需要的朋友可以參考下
    2017-09-09
  • idea中如何連接hive

    idea中如何連接hive

    這篇文章主要介紹了idea中如何連接hive問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 深入了解Java語言中的并發(fā)性選項有何不同

    深入了解Java語言中的并發(fā)性選項有何不同

    這篇文章主要介紹了深入了解Java語言中的并發(fā)性選項有何不同,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,,需要的朋友可以參考下
    2019-06-06
  • java必學必會之equals方法

    java必學必會之equals方法

    java必學必會之equals方法,equals方法是 java.lang.Object 類的方法,想要了解更多關于equals方法的朋友,可以參考下文
    2015-12-12
  • 解決Nacos集群啟動失敗:java版本問題

    解決Nacos集群啟動失敗:java版本問題

    這篇文章主要介紹了解決Nacos集群啟動失敗:java版本問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • Java代理深入講解之靜態(tài)代理

    Java代理深入講解之靜態(tài)代理

    這篇文章主要給大家介紹了關于Java靜態(tài)代理的相關資料,文中通過圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • springboot集成RestTemplate及常見的用法說明

    springboot集成RestTemplate及常見的用法說明

    這篇文章主要介紹了springboot集成RestTemplate及常見的用法說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java參數(shù)校驗詳解之使用@Valid注解和自定義注解進行參數(shù)驗證

    Java參數(shù)校驗詳解之使用@Valid注解和自定義注解進行參數(shù)驗證

    在后端開發(fā)中,參數(shù)校驗是非常普遍的,下面這篇文章主要給大家介紹了關于Java參數(shù)校驗詳解之使用@Valid注解和自定義注解進行參數(shù)驗證的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-06-06
  • java 使用foreach遍歷集合元素的實例

    java 使用foreach遍歷集合元素的實例

    這篇文章主要介紹了java 使用foreach遍歷集合元素的實例的相關資料,這里提供實例幫助大家理解如何使用foreach 進行遍歷,希望能幫助到大家,
    2017-08-08
  • Java利用Socket和IO流實現(xiàn)文件的上傳與下載

    Java利用Socket和IO流實現(xiàn)文件的上傳與下載

    本文主要介紹了Java利用Socket和IO流實現(xiàn)文件的上傳與下載,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04

最新評論

深州市| 萨嘎县| 修武县| 徐汇区| 河东区| 宁夏| 绥芬河市| 临邑县| 上犹县| 垦利县| 龙泉市| 武安市| 山阳县| 武鸣县| 逊克县| 安龙县| 文水县| 上思县| 巴彦淖尔市| 田林县| 常德市| 台北市| 文化| 尼勒克县| 巩留县| 阿巴嘎旗| 黎城县| 宜阳县| 马龙县| 肃南| 和田市| 嵊州市| 贵溪市| 宁化县| 河北区| 平乐县| 射阳县| 南和县| 彰化县| 海口市| 香格里拉县|