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

Java中Volatile的作用實例解析

 更新時間:2018年07月08日 16:50:36   作者:silion世  
本篇文章給大家通過實例分享了Java中Volatile的作用,有興趣的朋友可以學(xué)習(xí)參考下。

Java 語言中的 volatile 變量可以被看作是一種 “程度較輕的 synchronized”;與 synchronized 塊相比,volatile 變量所需的編碼較少,并且運行時開銷也較少,但是它所能實現(xiàn)的功能也僅是 synchronized 的一部分。

鎖提供了兩種主要特性:互斥(mutual exclusion) 和可見性(visibility)。

  • 互斥即一次只允許一個線程持有某個特定的鎖,因此可使用該特性實現(xiàn)對共享數(shù)據(jù)的協(xié)調(diào)訪問協(xié)議,這樣,一次就只有一個線程能夠使用該共享數(shù)據(jù)。
  • 可見性要更加復(fù)雜一些,它必須確保釋放鎖之前對共享數(shù)據(jù)做出的更改對于隨后獲得該鎖的另一個線程是可見的 —— 如果沒有同步機制提供的這種可見性保證,線程看到的共享變量可能是修改前的值或不一致的值,這將引發(fā)許多嚴(yán)重問題。

Volatile變量

volatile 變量具有 synchronized 的可見性特性,但是不具備原子特性。這就是說線程能夠自動發(fā)現(xiàn) volatile 變量的最新值。

Volatile 變量可用于提供線程安全,但是只能應(yīng)用于非常有限的一組用例:多個變量之間或者某個變量的當(dāng)前值與修改后值之間沒有約束。因此,單獨使用 volatile 還不足以實現(xiàn)計數(shù)器、互斥鎖或任何具有與多個變量相關(guān)的不變式(Invariants)的類(例如 “start <=end”)。

出于簡易性或可伸縮性的考慮,您可能傾向于使用 volatile 變量而不是鎖。當(dāng)使用 volatile 變量而非鎖時,某些習(xí)慣用法(idiom)更加易于編碼和閱讀。此外,volatile 變量不會像鎖那樣造成線程阻塞,因此也很少造成可伸縮性問題。在某些情況下,如果讀操作遠(yuǎn)遠(yuǎn)大于寫操作,volatile 變量還可以提供優(yōu)于鎖的性能優(yōu)勢。

正確使用 volatile 變量的條件

您只能在有限的一些情形下使用 volatile 變量替代鎖。要使 volatile 變量提供理想的線程安全,必須同時滿足下面兩個條件:
對變量的寫操作不依賴于當(dāng)前值。

該變量沒有包含在具有其他變量的不變式中。

實際上,這些條件表明,可以被寫入 volatile 變量的這些有效值獨立于任何程序的狀態(tài),包括變量的當(dāng)前狀態(tài)。

第一個條件的限制使 volatile 變量不能用作線程安全計數(shù)器。雖然增量操作(x++)看上去類似一個單獨操作,實際上它是一個由讀?。薷模瓕懭氩僮餍蛄薪M成的組合操作,必須以原子方式執(zhí)行,而 volatile 不能提供必須的原子特性。實現(xiàn)正確的操作需要使 x 的值在操作期間保持不變,而 volatile 變量無法實現(xiàn)這點。(然而,如果將值調(diào)整為只從單個線程寫入,那么可以忽略第一個條件。)

大多數(shù)編程情形都會與這兩個條件的其中之一沖突,使得 volatile 變量不能像 synchronized 那樣普遍適用于實現(xiàn)線程安全。清單 1 顯示了一個非線程安全的數(shù)值范圍類。它包含了一個不變式 —— 下界總是小于或等于上界。

舉例

下面看一個例子,我們實現(xiàn)一個計數(shù)器,每次線程啟動的時候,會調(diào)用計數(shù)器inc方法,對計數(shù)器進行加一
執(zhí)行環(huán)境——jdk版本:jdk1.6.0_31 ,內(nèi)存 :3G cpu:x86 2.4G

public class Counter { 

 public static int count = 0; 

 public static void inc() { 

  //這里延遲1毫秒,使得結(jié)果明顯 
  try { 
   Thread.sleep(1); 
  } catch (InterruptedException e) { 
  } 

  count++; 
 } 

 public static void main(String[] args) { 

  //同時啟動1000個線程,去進行i++計算,看看實際結(jié)果 

  for (int i = 0; i < 1000; i++) { 
   new Thread(new Runnable() { 
    @Override
    public void run() { 
     Counter.inc(); 
    } 
   }).start(); 
  } 

  //這里每次運行的值都有可能不同,可能為1000 
  System.out.println("運行結(jié)果:Counter.count=" + Counter.count); 
 } 
}

運行結(jié)果:Counter.count=995

實際運算結(jié)果每次可能都不一樣,本機的結(jié)果為:運行結(jié)果:Counter.count=995,可以看出,在多線程的環(huán)境下,Counter.count并沒有期望結(jié)果是1000

很多人以為,這個是多線程并發(fā)問題,只需要在變量count之前加上volatile就可以避免這個問題,那我們在修改代碼看看,看看結(jié)果是不是符合我們的期望

public class Counter { 

 public volatile static int count = 0; 

 public static void inc() { 

  //這里延遲1毫秒,使得結(jié)果明顯 
  try { 
   Thread.sleep(1); 
  } catch (InterruptedException e) { 
  } 

  count++; 
 } 

 public static void main(String[] args) { 

  //同時啟動1000個線程,去進行i++計算,看看實際結(jié)果 

  for (int i = 0; i < 1000; i++) { 
   new Thread(new Runnable() { 
    @Override
    public void run() { 
     Counter.inc(); 
    } 
   }).start(); 
  } 

  //這里每次運行的值都有可能不同,可能為1000 
  System.out.println("運行結(jié)果:Counter.count=" + Counter.count); 
 } 
}

運行結(jié)果:Counter.count=992

運行結(jié)果還是沒有我們期望的1000,下面我們分析一下原因

在 java 垃圾回收整理一文中,描述了jvm運行時刻內(nèi)存的分配。其中有一個內(nèi)存區(qū)域是jvm虛擬機棧,每一個線程運行時都有一個線程棧,線程棧保存了線程運行時候變量值信息。當(dāng)線程訪問某一個對象時候值的時候,首先通過對象的引用找到對應(yīng)在堆內(nèi)存的變量的值,然后把堆內(nèi)存變量的具體值load到線程本地內(nèi)存中,建立一個變量副本,之后線程就不再和對象在堆內(nèi)存變量值有任何關(guān)系,而是直接修改副本變量的值,在修改完之后的某一個時刻(線程退出之前),自動把線程變量副本的值回寫到對象在堆中變量。這樣在堆中的對象的值就產(chǎn)生變化了。下面一幅圖描述這寫交互

ead and load 從主存復(fù)制變量到當(dāng)前工作內(nèi)存

use and assign 執(zhí)行代碼,改變共享變量值

store and write 用工作內(nèi)存數(shù)據(jù)刷新主存相關(guān)內(nèi)容

其中use and assign 可以多次出現(xiàn)

但是這一些操作并不是原子性,也就是 在read load之后,如果主內(nèi)存count變量發(fā)生修改之后,線程工作內(nèi)存中的值由于已經(jīng)加載,不會產(chǎn)生對應(yīng)的變化,所以計算出來的結(jié)果會和預(yù)期不一樣

對于volatile修飾的變量,jvm虛擬機只是保證從主內(nèi)存加載到線程工作內(nèi)存的值是最新的

例如假如線程1,線程2 在進行read,load 操作中,發(fā)現(xiàn)主內(nèi)存中count的值都是5,那么都會加載這個最新的值

在線程1堆count進行修改之后,會write到主內(nèi)存中,主內(nèi)存中的count變量就會變?yōu)?

線程2由于已經(jīng)進行read,load操作,在進行運算之后,也會更新主內(nèi)存count的變量值為6

導(dǎo)致兩個線程及時用volatile關(guān)鍵字修改之后,還是會存在并發(fā)的情況。

相關(guān)文章

  • java 使用idea將工程打成jar并創(chuàng)建成exe文件類型執(zhí)行的方法詳解

    java 使用idea將工程打成jar并創(chuàng)建成exe文件類型執(zhí)行的方法詳解

    這篇文章主要介紹了java 使用idea將工程打成jar并創(chuàng)建成exe文件類型執(zhí)行,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2020-09-09
  • SpringBoot集成Redis使用Cache緩存的實現(xiàn)方法

    SpringBoot集成Redis使用Cache緩存的實現(xiàn)方法

    SpringBoot通過配置RedisConfig類和使用Cache注解可以輕松集成Redis實現(xiàn)緩存,主要包括@EnableCaching開啟緩存,自定義key生成器,改變序列化規(guī)則,以及配置RedisCacheManager,本文為使用SpringBoot與Redis處理緩存提供了詳實的指導(dǎo)和示例,感興趣的朋友一起看看吧
    2024-10-10
  • Java之HashMap.values()轉(zhuǎn)List時的錯誤和正確演示

    Java之HashMap.values()轉(zhuǎn)List時的錯誤和正確演示

    這篇文章主要介紹了Java之HashMap.values()轉(zhuǎn)List時的錯誤和正確演示,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java如何獲取Cookie和Session

    Java如何獲取Cookie和Session

    Cookie?和?Session之間主要是通過?SessionId?關(guān)聯(lián)起來的,?SessionId是?Cookie?和?Session?之間的橋梁,這篇文章主要介紹了Java獲取Cookie和Session的方法,需要的朋友可以參考下
    2024-01-01
  • MyEclipse如何取消默認(rèn)工作空間方法示例

    MyEclipse如何取消默認(rèn)工作空間方法示例

    這篇文章主要介紹了MyEclipse如何取消默認(rèn)工作空間,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-10-10
  • IDEA插件指南之Mybatis?log插件安裝及使用方法

    IDEA插件指南之Mybatis?log插件安裝及使用方法

    這篇文章主要給大家介紹了關(guān)于IDEA插件指南之Mybatis?log插件安裝及使用的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-02-02
  • java 中maven pom.xml文件教程詳解

    java 中maven pom.xml文件教程詳解

    這篇文章主要介紹了java 中maven pom.xml文件教程詳解,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-08-08
  • 深入理解Java動態(tài)代理與靜態(tài)代理

    深入理解Java動態(tài)代理與靜態(tài)代理

    這篇文章主要介紹了深入理解Java動態(tài)代理與靜態(tài)代理,靜態(tài)代理,代理類和被代理的類實現(xiàn)了同樣的接口,代理類同時持有被代理類的引用,動態(tài)代理的根據(jù)實現(xiàn)方式的不同可以分為JDK動態(tài)代理和CGlib動態(tài)代理
    2022-06-06
  • java實現(xiàn)微信紅包 拼手氣紅包

    java實現(xiàn)微信紅包 拼手氣紅包

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)微信紅包,拼手氣紅包,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • MyBatis-Plus執(zhí)行SQL分析打印過程

    MyBatis-Plus執(zhí)行SQL分析打印過程

    這篇文章主要介紹了MyBatis-Plus執(zhí)行SQL分析打印過程,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09

最新評論