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

深入解析Java中volatile關(guān)鍵字的作用

 更新時間:2013年09月06日 17:35:14   作者:  
Java語言是支持多線程的,為了解決線程并發(fā)的問題,在語言內(nèi)部引入了 同步塊 和 volatile 關(guān)鍵字機制

在java線程并發(fā)處理中,有一個關(guān)鍵字volatile的使用目前存在很大的混淆,以為使用這個關(guān)鍵字,在進行多線程并發(fā)處理的時候就可以萬事大吉。

Java語言是支持多線程的,為了解決線程并發(fā)的問題,在語言內(nèi)部引入了 同步塊 和 volatile 關(guān)鍵字機制。

synchronized
同步塊大家都比較熟悉,通過 synchronized 關(guān)鍵字來實現(xiàn),所有加上synchronized 和 塊語句,在多線程訪問的時候,同一時刻只能有一個線程能夠用synchronized 修飾的方法 或者 代碼塊。

volatile
用volatile修飾的變量,線程在每次使用變量的時候,都會讀取變量修改后的最的值。volatile很容易被誤用,用來進行原子性操作。

下面看一個例子,我們實現(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虛擬機棧,每一個線程運行時都有一個線程棧,線程棧保存了線程運行時候變量值信息。當線程訪問某一個對象時候值的時候,首先通過對象的引用找到對應(yīng)在堆內(nèi)存的變量的值,然后把堆內(nèi)存變量的具體值load到線程本地內(nèi)存中,建立一個變量副本,之后線程就不再和對象在堆內(nèi)存變量值有任何關(guān)系,而是直接修改副本變量的值,在修改完之后的某一個時刻(線程退出之前),自動把線程變量副本的值回寫到對象在堆中變量。這樣在堆中的對象的值就產(chǎn)生變化了。下面一幅圖

描述這寫交互

java volatile1

read and load 從主存復制變量到當前工作內(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é)果會和預期不一樣

對于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

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

相關(guān)文章

  • JAVA 添加、修改和刪除PDF書簽的示例代碼

    JAVA 添加、修改和刪除PDF書簽的示例代碼

    這篇文章主要介紹了JAVA 添加、修改和刪除PDF書簽的示例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-06-06
  • Spring中將Service注入到Servlet中的四種方法

    Spring中將Service注入到Servlet中的四種方法

    在Spring中,如果需要將Service注入到Servlet中,可以通過以下幾種方法實現(xiàn),Spring本身提供了對Servlet的集成能力,因此可以結(jié)合Spring的依賴注入機制,將Service類注入到Servlet中,需要的朋友可以參考下
    2025-05-05
  • SpringBoot應(yīng)用是否存在MySQL連接泄漏問題的排查方法

    SpringBoot應(yīng)用是否存在MySQL連接泄漏問題的排查方法

    這篇文章主要介紹了排查SpringBoot應(yīng)用MySQL連接泄漏的方法,需檢查連接數(shù)、空閑連接,配置連接池參數(shù),確保資源關(guān)閉,并使用監(jiān)控工具如Actuator和Prometheus分析,需要的朋友可以參考下
    2025-06-06
  • Spring Gateway的入門概述及主要功能

    Spring Gateway的入門概述及主要功能

    Spring Gateway是Spring Cloud微服務(wù)生態(tài)下的網(wǎng)關(guān)組件,網(wǎng)絡(luò)層使用了基于非阻塞的 Netty使用異步IO增加了系統(tǒng)的性能,Gateway 是基于 Spring 5 和 Spring Boot 2 搭建的,這篇文章主要介紹了Spring Gateway的入門概述簡介,需要的朋友可以參考下
    2024-04-04
  • Java中字符串替換的4種方法代碼舉例

    Java中字符串替換的4種方法代碼舉例

    這篇文章主要介紹了Java中四種字符串替換方法,分別是String.replace()、String.replaceAll()、String.replaceFirst()和StringBuilder.replace(),并對比了它們的特點和適用場景,需要的朋友可以參考下
    2025-02-02
  • 深入理解Java對象的序列化與反序列化的應(yīng)用

    深入理解Java對象的序列化與反序列化的應(yīng)用

    本篇文章是對Java中對象的序列化與反序列化進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • Java利用Spire.PDF for Java將PDF轉(zhuǎn)換為Excel的實現(xiàn)方法

    Java利用Spire.PDF for Java將PDF轉(zhuǎn)換為Excel的實現(xiàn)方法

    在Java生態(tài)中,有多種庫可以處理PDF文件,但要實現(xiàn)高質(zhì)量的PDF到Excel轉(zhuǎn)換,Spire.PDF for Java是一個功能全面且性能優(yōu)越的工具,所以本文給大家介紹了Java如何利用Spire.PDF for Java將PDF轉(zhuǎn)換為Excel的實現(xiàn)方法,需要的朋友可以參考下
    2025-09-09
  • java 出現(xiàn)Zipexception 異常的解決辦法

    java 出現(xiàn)Zipexception 異常的解決辦法

    這篇文章主要介紹了java 出現(xiàn)Zipexception 異常的解決辦法的相關(guān)資料,出現(xiàn) java.util.zip.ZipException: error in opening zip file 異常的原因及解決方法,需要的朋友可以參考下
    2017-08-08
  • Java編程反射機制用法入門與實例總結(jié)

    Java編程反射機制用法入門與實例總結(jié)

    這篇文章主要介紹了Java編程反射機制用法,簡單說明了反射機制的概念、原理并結(jié)合實例形式總結(jié)分析了java反射機制的簡單使用方法與相關(guān)注意事項,需要的朋友可以參考下
    2017-12-12
  • 淺談Spring解決jar包依賴的bom

    淺談Spring解決jar包依賴的bom

    這篇文章主要介紹了淺談Spring解決jar包依賴的bom,具有一定借鑒價值,需要的朋友可以參考下
    2017-12-12

最新評論

鹤岗市| 伊通| 道孚县| 绥化市| 秭归县| 多伦县| 都江堰市| 武汉市| 舒城县| 广安市| 太谷县| 连州市| 若尔盖县| 清水县| 海门市| 龙井市| 上饶县| 会东县| 鹤峰县| 芦山县| 安溪县| 莒南县| 东海县| 社会| 富顺县| 堆龙德庆县| 台湾省| 永福县| 灌南县| 金堂县| 仙居县| 东城区| 改则县| 靖边县| 永新县| 静安区| 云安县| 武川县| 邵武市| 梧州市| 沙雅县|