本篇文章為大家展示了深入淺析Java中的共享對(duì)象和存儲(chǔ)模型,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
在郊區(qū)等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì) 網(wǎng)站設(shè)計(jì)制作按需網(wǎng)站策劃,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),營(yíng)銷型網(wǎng)站,外貿(mào)營(yíng)銷網(wǎng)站建設(shè),郊區(qū)網(wǎng)站建設(shè)費(fèi)用合理。
Java 存儲(chǔ)模型和共享對(duì)象詳解
很多程序員對(duì)一個(gè)共享變量初始化要注意可見性和安全發(fā)布(安全地構(gòu)建一個(gè)對(duì)象,并其他線程能正確訪問)等問題不是很理解,認(rèn)為Java是一個(gè)屏蔽內(nèi)存細(xì)節(jié)的平臺(tái),連對(duì)象回收都不需要關(guān)心,因此談到可見性和安全發(fā)布大多不知所云。其實(shí)關(guān)鍵在于對(duì)Java存儲(chǔ)模型,可見性和安全發(fā)布的問題是起源于Java的存儲(chǔ)結(jié)構(gòu)。
Java存儲(chǔ)模型原理
有很多書和文章都講解過Java存儲(chǔ)模型,其中一個(gè)圖很清晰地說明了其存儲(chǔ)結(jié)構(gòu):

由上圖可知, jvm系統(tǒng)中存在一個(gè)主內(nèi)存(Main Memory或Java Heap Memory),Java中所有變量都儲(chǔ)存在主存中,對(duì)于所有線程都是共享的。 每條線程都有自己的工作內(nèi)存(Working Memory),工作內(nèi)存中保存的是主存中某些變量的拷貝,線程對(duì)所有變量的操作都是在工作內(nèi)存中進(jìn)行,線程之間無法相互直接訪問,變量傳遞均需要通過主存完成。
這個(gè)存儲(chǔ)模型很像我們常用的緩存與數(shù)據(jù)庫(kù)的關(guān)系,因此由此可以推斷JVM如此設(shè)計(jì)應(yīng)該是為了提升性能,提高多線程的并發(fā)能力,并減少線程之間的影響。
Java存儲(chǔ)模型潛在的問題
一談到緩存, 我們立馬想到會(huì)有緩存不一致性問題,就是說當(dāng)有緩存與數(shù)據(jù)庫(kù)不一致的時(shí)候,就需要有相應(yīng)的機(jī)制去同步數(shù)據(jù)。同理,Java存儲(chǔ)模型也有這個(gè)問題,當(dāng)一個(gè)線程在自己工作內(nèi)存里初始化一個(gè)變量,當(dāng)還沒來得及同步到主存里時(shí),如果有其他線程來訪問它,就會(huì)出現(xiàn)不可預(yù)知的問題。另外,JVM在底層設(shè)計(jì)上,對(duì)與那些沒有同步到主存里的變量,可能會(huì)以不一樣的操作順序來執(zhí)行指令,舉個(gè)實(shí)際的例子:
public class PossibleReordering {
static int x = 0, y = 0;
static int a = 0, b = 0;
public static void main(String[] args)
throws InterruptedException {
Thread one = new Thread(new Runnable() {
public void run() {
a = 1;
x = b;
}
});
Thread other = new Thread(new Runnable() {
public void run() {
b = 1;
y = a;
}
});
one.start(); other.start();
one.join(); other.join();
System.out.println("( "+ x + "," + y + ")");
}
}
由于,變量x,y,a,b沒有安全發(fā)布,導(dǎo)致會(huì)不以規(guī)定的操作順序來執(zhí)行這次四次賦值操作,有可能出現(xiàn)以下順序:

出現(xiàn)這個(gè)問題也可以理解,因?yàn)榧热贿@些對(duì)象不可見,也就是說本應(yīng)該隔離在各個(gè)線程的工作區(qū)內(nèi),那么對(duì)于有些無關(guān)順序的指令,打亂順序執(zhí)行在JVM看來也是可行的。
因此,總結(jié)起來,會(huì)有以下兩種潛在問題:
解決Java存儲(chǔ)模型潛在的問題
為了能讓開發(fā)人員安全正確地在Java存儲(chǔ)模型上編程,JVM提供了一個(gè)happens-before原則,有人整理得非常好,我摘抄如下:
有了原則還不夠,Java提供了以下工具和方法來保證變量的可見性和安全發(fā)布:
另外,一定要明確只有共享變量才會(huì)有以上那些問題,如果變量只是這個(gè)線程自己使用,就不用擔(dān)心那么多問題了
搞清楚Java存儲(chǔ)模型后,再來看共享對(duì)象可見性和安全發(fā)布的問題就較為容易了
共享對(duì)象的可見性
當(dāng)對(duì)象在從工作內(nèi)存同步到主內(nèi)存之前,那么它就是不可見的。若有其他線程在存取不可見對(duì)象就會(huì)引發(fā)可見性問題,看下面一個(gè)例子:
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
按照正常邏輯,應(yīng)該會(huì)輸出42,但其實(shí)際結(jié)果會(huì)非常奇怪,可能會(huì)永遠(yuǎn)沒有輸出(因?yàn)閞eady為false),可能會(huì)輸出0(因?yàn)橹嘏判騿栴}導(dǎo)致ready=true先執(zhí)行)。再舉一個(gè)更為常見的例子,大家都喜歡用只有set和get方法的pojo來設(shè)計(jì)領(lǐng)域模型,如下所示:
@NotThreadSafe
public class MutableInteger {
private int value;
public int get() { return value; }
public void set(int value) { this.value = value; }
}
但是,當(dāng)有多個(gè)線程同時(shí)來存取某一個(gè)對(duì)象時(shí),可能就會(huì)有類似的可見性問題。
為了保證變量的可見性,一般可以用鎖、 synchronized關(guān)鍵字、 volatile關(guān)鍵字或直接設(shè)置為final
共享變量發(fā)布
共享變量發(fā)布和我們常說的發(fā)布程序類似,就是說讓本屬于內(nèi)部的一個(gè)變量變?yōu)橐粋€(gè)可以被外部訪問的變量。發(fā)布方式分為以下幾種:
安全發(fā)布和保證可見性的方法類似,就是要同步發(fā)布動(dòng)作,并使發(fā)布后的對(duì)象可見。
線程安全
其實(shí)當(dāng)我們把這些變量封閉在本線程內(nèi)訪問,就可以從根本上避免以上問題,現(xiàn)實(shí)中存在很多例子通過線程封閉來安全使用本不是線程安全的對(duì)象,比如:
上述內(nèi)容就是深入淺析Java中的共享對(duì)象和存儲(chǔ)模型,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
網(wǎng)站名稱:深入淺析Java中的共享對(duì)象和存儲(chǔ)模型
文章URL:http://chinadenli.net/article10/jgjdgo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供電子商務(wù)、小程序開發(fā)、外貿(mào)建站、App開發(fā)、網(wǎng)站內(nèi)鏈、動(dòng)態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)