欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

一、volatile關(guān)鍵字

volatile是JVM提供的一種輕量級(jí)的同步機(jī)制,特性:

1.保證內(nèi)存可見(jiàn)性

2.不保證原子性

3.防止指令重排序

二、JMM(Java Memory Model)

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

三、驗(yàn)證

1.驗(yàn)證volatile的可見(jiàn)性

1.1 假如 int num = 0; num變量之前根本沒(méi)有添加volatile關(guān)鍵字修飾,沒(méi)有可見(jiàn)性

1.2 添加了volatile,可以解決可見(jiàn)性問(wèn)題

MyData類

class MyData {
 volatile int num = 0;

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

內(nèi)存可見(jiàn)性驗(yàn)證,其中兩個(gè)線程分別為AAA線程和main線程

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

 new Thread(() -> {
  System.out.println(Thread.currentThread().getName() + "\t come in");
  //暫停一會(huì)線程
  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個(gè)線程是我們的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 );
 }

對(duì)num變量加volatile修飾后結(jié)果

AAA come in
AAA update num value: 60
main 我能見(jiàn)到AAA線程對(duì)num修改的結(jié)果啦,main get num value: 60

Process finished with exit code 0

2.驗(yàn)證volatile不保證原子性

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

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

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

2.3 為什么不保證原子性?

2.4 如何保證原子性

加sync

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

給MyData類加addPlusPlus()方法

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

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

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

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

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

創(chuàng)建20個(gè)線程并行執(zhí)行num++操作2000次,多次測(cè)試,結(jié)果不為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個(gè)線程都全部計(jì)算完成后,再用main線程取得最終的結(jié)果值看是多少?
 while(Thread.activeCount() > 2) {
  Thread.yield();
 }

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

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

main  finally num value:38480

Process finished with exit code 0

2.3 為什么不保證原子性?

因?yàn)楫?dāng)線程A對(duì)num++操作從自己的工作內(nèi)存刷新到主內(nèi)存時(shí),還未通知到其他線程主內(nèi)存變量有更新的瞬間,其他線程對(duì)num變量的操作結(jié)果也對(duì)主內(nèi)存進(jìn)行了刷新,從而導(dǎo)致了寫值丟失的情況

num++通過(guò)匯編指令分析,通過(guò)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
}

可見(jiàn)num++被拆分成了3個(gè)步驟,簡(jiǎn)稱:讀-改-寫

  • 執(zhí)行g(shù)etfield拿到原始num;
  • 執(zhí)行iadd進(jìn)行加1操作;
  • 執(zhí)行putfield寫把累加后的值寫回

2.4 如何保證原子性

加sync

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

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

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

調(diào)用該方法打印結(jié)果

 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個(gè)線程都全部計(jì)算完成后,再用main線程取得最終的結(jié)果值看是多少?
 while(Thread.activeCount() > 2) {
  Thread.yield();
 }

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

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

main  AtomicInteger type ,finally num value:40000

Process finished with exit code 0

總結(jié)

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

相關(guān)文章

  • 深入學(xué)習(xí)JavaWeb中監(jiān)聽(tīng)器(Listener)的使用方法

    深入學(xué)習(xí)JavaWeb中監(jiān)聽(tīng)器(Listener)的使用方法

    這篇文章主要為大家詳細(xì)介紹了深入學(xué)習(xí)JavaWeb中監(jiān)聽(tīng)器(Listener)的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • 解決JavaMail附件名字過(guò)長(zhǎng)導(dǎo)致的亂碼問(wèn)題

    解決JavaMail附件名字過(guò)長(zhǎng)導(dǎo)致的亂碼問(wèn)題

    這篇文章主要介紹了解決JavaMail附件名字過(guò)長(zhǎng)導(dǎo)致的亂碼問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-10-10
  • Java連接超時(shí)的幾種情況以及讀取代碼

    Java連接超時(shí)的幾種情況以及讀取代碼

    在Java編程中連接超時(shí)異常是指在建立網(wǎng)絡(luò)連接時(shí),無(wú)法在給定的時(shí)間內(nèi)成功建立連接的異常,這篇文章主要給大家介紹了關(guān)于Java連接超時(shí)的幾種情況以及讀取的相關(guān)資料,需要的朋友可以參考下
    2024-02-02
  • Java的SPI機(jī)制實(shí)例詳解

    Java的SPI機(jī)制實(shí)例詳解

    這篇文章主要介紹了Java的SPI機(jī)制實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • Java實(shí)現(xiàn)單向鏈表的基本功能詳解

    Java實(shí)現(xiàn)單向鏈表的基本功能詳解

    這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)單向鏈表基本功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03
  • Java求素?cái)?shù)和最大公約數(shù)的簡(jiǎn)單代碼示例

    Java求素?cái)?shù)和最大公約數(shù)的簡(jiǎn)單代碼示例

    這篇文章主要介紹了Java求素?cái)?shù)和最大公約數(shù)的簡(jiǎn)單代碼示例,其中作者創(chuàng)建的Fraction類可以用來(lái)進(jìn)行各種分?jǐn)?shù)運(yùn)算,需要的朋友可以參考下
    2015-09-09
  • 淺析Java單例設(shè)計(jì)模式(自寫demo)

    淺析Java單例設(shè)計(jì)模式(自寫demo)

    Java單例模式是看起來(lái)以及用起來(lái)簡(jiǎn)單的一種設(shè)計(jì)模式,但是就實(shí)現(xiàn)方式以及原理來(lái)說(shuō),也并不淺顯,下面這篇文章主要給大家詳細(xì)介紹了Java中單例模式,需要的朋友可以參考下
    2021-12-12
  • Java實(shí)現(xiàn)瀏覽器端大文件分片上傳

    Java實(shí)現(xiàn)瀏覽器端大文件分片上傳

    本文主要介紹了Java實(shí)現(xiàn)瀏覽器端大文件分片上傳,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Java實(shí)現(xiàn)EasyCaptcha圖形驗(yàn)證碼的具體使用

    Java實(shí)現(xiàn)EasyCaptcha圖形驗(yàn)證碼的具體使用

    Java圖形驗(yàn)證碼,支持gif、中文、算術(shù)等類型,可用于Java Web、JavaSE等項(xiàng)目,下面就跟隨小編一起來(lái)了解一下
    2021-08-08
  • SparkStreaming整合Kafka過(guò)程詳解

    SparkStreaming整合Kafka過(guò)程詳解

    這篇文章主要介紹了SparkStreaming整合Kafka過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2023-01-01

最新評(píng)論