淺析java volatitle 多線程問(wèn)題
我們知道,在Java中設(shè)置變量值的操作,除了long和double類型的變量外都是原子操作,也就是說(shuō),對(duì)于變量值的簡(jiǎn)單讀寫(xiě)操作沒(méi)有必要進(jìn)行同步。
這在JVM 1.2之前,Java的內(nèi)存模型實(shí)現(xiàn)總是從主存讀取變量,是不需要進(jìn)行特別的注意的。而隨著JVM的成熟和優(yōu)化,現(xiàn)在在多線程環(huán)境下volatile關(guān)鍵字的使用變得非常重要。在當(dāng)前的Java內(nèi)存模型下,線程可以把變量保存在本地內(nèi)存(比如機(jī)器的寄存器)中,而不是直接在主存中進(jìn)行讀寫(xiě)。這就可能造成一個(gè)線程在主存中修改了一個(gè)變量的值,而另外一個(gè)線程還繼續(xù)使用它在寄存器中的變量值的拷貝,造成數(shù)據(jù)的不一致。要解決這個(gè)問(wèn)題,只需要像在本程序中的這樣,把該變量聲明為volatile(不穩(wěn)定的)即可,這就指示JVM,這個(gè)變量是不穩(wěn)定的,每次使用它都到主存中進(jìn)行讀取。一般說(shuō)
來(lái),多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志都應(yīng)該加volatile修飾。
Volatile修飾的成員變量在每次被線程訪問(wèn)時(shí),都強(qiáng)迫從共享內(nèi)存中重讀該成員變量的值。而且,當(dāng)成員變量發(fā)生變化時(shí),強(qiáng)迫線程將變化值回寫(xiě)到共享內(nèi)存。這樣在任何時(shí)刻,兩個(gè)不同的線程總是看到某個(gè)成員變量的同一個(gè)值。
Java語(yǔ)言規(guī)范中指出:為了獲得最佳速度,允許線程保存共享成員變量的私有拷貝,而且只當(dāng)線程進(jìn)入或者離開(kāi)同步代碼塊時(shí)才與共享成員變量的原始值對(duì)比。
這樣當(dāng)多個(gè)線程同時(shí)與某個(gè)對(duì)象交互時(shí),就必須要注意到要讓線程及時(shí)的得到共享成員變量的變化。
而volatile關(guān)鍵字就是提示VM:對(duì)于這個(gè)成員變量不能保存它的私有拷貝,而應(yīng)直接與共享成員變量交互。
使用建議:在兩個(gè)或者更多的線程訪問(wèn)的成員變量上使用volatile。當(dāng)要訪問(wèn)的變量已在synchronized代碼塊中,或者為常量時(shí),不必使用。
由于使用volatile屏蔽掉了VM中必要的代碼優(yōu)化,所以在效率上比較低,因此一定在必要時(shí)才使用此關(guān)鍵字。
在虛擬機(jī)的實(shí)現(xiàn)中,int,char等基本類型為一個(gè)字長(zhǎng)。而long和double占兩個(gè)字長(zhǎng)。在某些虛擬機(jī)的實(shí)現(xiàn)中,兩個(gè)字長(zhǎng)可能會(huì)被作為兩個(gè)原子性的單字長(zhǎng)來(lái)操作。
如果不以volatile修飾long和double,如果多線程訪問(wèn)該變量,由于long操作的整體非原子性而導(dǎo)致結(jié)果混亂。
比如:int,一個(gè)線程寫(xiě)入4,另一個(gè)寫(xiě)入5. 最后肯定是4或者5.而 long型,可能就是個(gè)亂七八糟的數(shù)值了。
- java多線程和并發(fā)包入門(mén)示例
- java多線程詳細(xì)總結(jié)
- Java 多線程同步 鎖機(jī)制與synchronized深入解析
- JAVA多線程與并發(fā)學(xué)習(xí)總結(jié)分析
- JAVA實(shí)現(xiàn)多線程的兩種方法實(shí)例分享
- java多線程之wait(),notify(),notifyAll()的詳解分析
- 基于Java多線程notify與notifyall的區(qū)別分析
- 基于Java回顧之多線程同步的使用詳解
- 基于Java回顧之多線程詳解
- Java多線程之中斷線程(Interrupt)的使用詳解
- Java多線程的用法詳解
- java Thread 多線程
- Java多線程下載的實(shí)現(xiàn)方法
- java多線程復(fù)制文件的實(shí)例代碼
- JAVA多線程Thread和Runnable的實(shí)現(xiàn)
- 使用java實(shí)現(xiàn)http多線程斷點(diǎn)下載文件(二)
- 使用java實(shí)現(xiàn)http多線程斷點(diǎn)下載文件(一)
- 哲學(xué)家就餐問(wèn)題中的JAVA多線程學(xué)習(xí)
相關(guān)文章
J2SE基礎(chǔ)之命令行中編寫(xiě)第一個(gè) Hello World
“Hello World”程序指的是只在計(jì)算機(jī)屏幕上輸出“Hello, World!”(意為“世界,你好!”)這行字符串的計(jì)算機(jī)程序。hello world作為所有編程語(yǔ)言的起始階段,占據(jù)著無(wú)法改變的地位,所有的編程第一步就在于此了!經(jīng)典之中的經(jīng)典!hello world!2016-05-05
NetBeans安裝提示neatbeans cannot find java 1.8 or higher
今天小編就為大家分享一篇關(guān)于NetBeans安裝提示neatbeans cannot find java 1.8 or higher,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-04-04
詳解SpringMVC中設(shè)置靜態(tài)資源不被攔截的問(wèn)題
這篇文章主要介紹了詳解SpringMVC中設(shè)置靜態(tài)資源不被攔截的問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
SpringBoot?+?Redis如何解決重復(fù)提交問(wèn)題(冪等)
在開(kāi)發(fā)中,一個(gè)對(duì)外暴露的接口可能會(huì)面臨瞬間的大量重復(fù)請(qǐng)求,本文就介紹了SpringBoot + Redis如何解決重復(fù)提交問(wèn)題,具有一定的參考價(jià)值,感興趣的可以了解一下2021-12-12
詳解Spring Boot實(shí)戰(zhàn)之Restful API的構(gòu)建
這篇文章主要介紹了詳解Spring Boot實(shí)戰(zhàn)之Restful API的構(gòu)建,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
java實(shí)現(xiàn)自定義時(shí)鐘并實(shí)現(xiàn)走時(shí)功能
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)自定義時(shí)鐘并實(shí)現(xiàn)走時(shí)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06

