溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java并發(fā)編程之關(guān)鍵字volatile的示例分析

發(fā)布時(shí)間:2021-06-09 09:53:54 來(lái)源:億速云 閱讀:145 作者:小新 欄目:開發(fā)技術(shù)

這篇文章給大家分享的是有關(guān)Java并發(fā)編程之關(guān)鍵字volatile的示例分析的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。

一、作用

被 volatile 修飾的變量

1.保證了不同線程對(duì)該變量操作的內(nèi)存可見性

2.禁止指令重排序

二、可見性

Java并發(fā)編程之關(guān)鍵字volatile的示例分析

Java 內(nèi)存模型(Java Memory Model) 是 Java 虛擬機(jī)定義的一種規(guī)范,即每個(gè)線程都有自己的工作空間,線程對(duì)變量的操作都在線程的工作內(nèi)存中完成,再同步到主存中,這樣可能會(huì)導(dǎo)致不同的線程對(duì)共享變量的操作,在各自線程工作空間內(nèi)不一樣的問(wèn)題。

而用 volatile 修飾的變量,線程對(duì)該變量的修改,會(huì)立刻刷新到主存,其它線程讀取該變量時(shí),會(huì)重新去主存讀取新值。

三、有序性

CPU 為了提供程序的運(yùn)行效率,會(huì)對(duì)代碼的執(zhí)行順序進(jìn)行重排,因此代碼中各個(gè)語(yǔ)句的先后執(zhí)行順序有可能會(huì)變化,但是它會(huì)保證程序最終執(zhí)行結(jié)果與代碼順序執(zhí)行結(jié)果一致。

指令重排序會(huì)考慮數(shù)據(jù)之間的依賴性,不會(huì)影響單個(gè)線程內(nèi)程序的執(zhí)行結(jié)果

c = 2 可能在 a = 1之前執(zhí)行

int a = 1;
int c = 2;

volatile 修飾的變量具有有序性,即被 volatile 修飾的變量,在其前面的操作與在其后面的操作的執(zhí)行順序不能打亂。

int a= 1;
volatile b = 2;
int c = 2;

a = 1 一定在 c = 2 前面執(zhí)行,volatile 的作用好像在兩者之間插入了一個(gè)內(nèi)存屏障

對(duì)于 volatile 的有序性應(yīng)用,一般常用 double-check 的單例模式來(lái)說(shuō)明

public class Singleton {
	private Singleton(){}

	private static volatile Singleton singleton;
	
	public static Singleton getSingleton(){
		if (singleton == null){
			synchronized(Singleton.class){
				if (singleton == null){
					singleton = new Singleton();
				}
			}
		}
		return singleton		
	}
}

singleton = new Singleton(); 分為 3 步

1.new Singleton() 開辟堆內(nèi)存空間

2.初始化 singleton 對(duì)象

3.將 singleton 對(duì)象指向堆內(nèi)存地址

第 3 步可能在第 2 步之前執(zhí)行,那么其它線程可能得到為初始化完成的 singleton 對(duì)象,造成異常。

四、happens-before

  • 程序順序規(guī)則: 一個(gè)線程中的每個(gè)操作,happens-before于該線程中的任意后續(xù)操作

  • 監(jiān)視器鎖規(guī)則:對(duì)一個(gè)線程的解鎖,happens-before 于隨后對(duì)這個(gè)線程的加鎖

  • volatile 變量規(guī)則: 對(duì)一個(gè) volatile 域的寫,happens-before 于后續(xù)對(duì)這個(gè) volatile 域的讀

  • 傳遞性:如果 A happens-before B ,且 B happens-before C, 那么 A happens-before C

  • start()規(guī)則: 如果線程A執(zhí)行操作ThreadB_start()(啟動(dòng)線程B) , 那么A線程的ThreadB_start()happens-before 于B中的任意操作

  • join()原則: 如果A執(zhí)行ThreadB.join()并且成功返回,那么線程B中的任意操作happens-before于線程A從ThreadB.join()操作成功返回。

  • interrupt()原則: 對(duì)線程interrupt()方法的調(diào)用先行發(fā)生于被中斷線程代碼檢測(cè)到中斷事件的發(fā)生,可以通過(guò)Thread.interrupted()方法檢測(cè)是否有中斷發(fā)生

  • finalize()原則:一個(gè)對(duì)象的初始化完成先行發(fā)生于它的finalize()方法的開始

五、與 Synchronized 對(duì)比

1.volatile 只能作用于變量,synchronized 可以作用于變量,方法,代碼塊

2.volatile 不保證原子性,synchronized 可以保證

3.訪問(wèn) volatile 修飾的變量不會(huì)阻塞,synchronized 可能會(huì)

感謝各位的閱讀!關(guān)于“Java并發(fā)編程之關(guān)鍵字volatile的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI