久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

java的可見(jiàn)性,、有序性和原子性

 昵稱60891057 2018-12-01

話不多說(shuō),,先上一張圖

java內(nèi)存模(jie)型(gou)

沒(méi)錯(cuò),我們今天聊的東西,,跟他沒(méi)啥關(guān)系,。

上面這是java的內(nèi)存結(jié)構(gòu)(我就是忽悠你們來(lái)的)。

今兒主要先聊一聊java的內(nèi)存模型(嗯,,也不是非想跟你們聊,,主要是標(biāo)題得從這玩意兒來(lái)引出)。

但是也不能干聊不是,?想起兄弟們?cè)?jīng)對(duì)我靈魂的拷問(wèn)(無(wú)圖言屌),,所以我就又從網(wǎng)上盜了一張圖。

來(lái)來(lái)來(lái),,看圖說(shuō)話:

java真·內(nèi)存模型

1.java中所有的變量都是存在主內(nèi)存里的,。

2.各自的線程在工作的時(shí)候會(huì)自己拿到一塊工作內(nèi)存。里面保存了該線程用到的變量的副本,。

3.線程對(duì)變量的操作,,都是對(duì)自己工作內(nèi)存中變量的操作,不能操作主內(nèi)存,。

4.最終工作內(nèi)存中的數(shù)據(jù)是需要同步回主內(nèi)存,,來(lái)完成主內(nèi)存中變量的更新的。

舉個(gè)例子吧:

就好比主內(nèi)存就是大哥,,線程就是小弟,,大哥每天督促小弟們干活,小弟們彼此不怎么交流,,每天就是干了活,,然后自己找個(gè)本記下來(lái),找時(shí)間告訴大哥,。

那么咱們來(lái)看下面的這一個(gè)場(chǎng)景:

大哥說(shuō)讓仨小弟進(jìn)點(diǎn)兒貨,。讓一個(gè)小弟聯(lián)系貨源,一個(gè)小弟聯(lián)系運(yùn)輸公司,,一個(gè)小弟聯(lián)系裝卸工,。小弟1去聯(lián)系貨源了,聯(lián)系好了告訴大哥,,“貨源聯(lián)系好了”,。這時(shí)候小弟2來(lái)了,一聽(tīng)貨源好了,,就去聯(lián)系運(yùn)輸公司了,。運(yùn)輸公司聯(lián)系好了,小弟2還沒(méi)回去告訴大哥呢,,小弟3跑過(guò)去問(wèn)大哥了,,一聽(tīng)大哥說(shuō)貨源好了,,也跑出去聯(lián)系運(yùn)輸公司了。結(jié)果來(lái)了倆運(yùn)輸公司,,對(duì)著成堆的貨物干瞪眼,。

這里面有幾個(gè)問(wèn)題呢?

1.小弟2忙活清了,,應(yīng)該打個(gè)電話趕緊通知大哥,,他找到運(yùn)輸公司了。

2.大哥知道小弟2出去忙活事情了,,小弟3這時(shí)候來(lái)了,,大哥應(yīng)該別讓小弟3著急,等小弟2干完了,,小弟3再上,。

3.小弟2要是告訴大哥,他出去找運(yùn)輸公司了,,大哥怎么還會(huì)讓小弟3接著去找運(yùn)輸公司呢,?

如果在這個(gè)場(chǎng)景里,我們會(huì)說(shuō),,這不一群智障么,,這種錯(cuò)誤都能發(fā)生,辦事不過(guò)腦子的么,?,!

是的,java就是這么的智障,。

其實(shí)呢,,上面闡述的三個(gè)問(wèn)題,,也就是我們java內(nèi)存模型在設(shè)計(jì)的時(shí)候,,所圍繞的三個(gè)問(wèn)題:

可見(jiàn)性,有序性和原子性,。(終于聊到重點(diǎn)了朋友們?。?/strong>

下面要上定義了!

可見(jiàn)性:一個(gè)線程對(duì)共享變量做了修改之后,,其他的線程立即能夠看到(感知到)該變量這種修改(變化),。

Java內(nèi)存模型是通過(guò)將在工作內(nèi)存中的變量修改后的值同步到主內(nèi)存,在讀取變量前從主內(nèi)存刷新最新值到工作內(nèi)存中,,這種依賴主內(nèi)存的方式來(lái)實(shí)現(xiàn)可見(jiàn)性的,。

有序性:在本線程內(nèi)觀察,操作都是有序的,;如果在一個(gè)線程中觀察另外一個(gè)線程,,所有的操作都是無(wú)序的,。

java內(nèi)存模型所保證的是,同線程內(nèi),,所有的操作都是由上到下的,,但是多個(gè)線程并行的情況下,則不能保證其操作的有序性,。

原子性:一個(gè)操作不能被打斷,,要么全部執(zhí)行完畢,要么不執(zhí)行,。

基本數(shù)據(jù)類型的訪問(wèn)都是原子性的(默認(rèn)64位,,32位的機(jī)器對(duì)long、double這種占8個(gè)字節(jié)的是非原子性的),,而針對(duì)非原子性的數(shù)據(jù),,多線程的訪問(wèn)則是不安全的。

以上是java內(nèi)存模型中,,單線程針對(duì)這三種問(wèn)題作出的最基本的控制,,但是并發(fā)編程的場(chǎng)景中, 多線程的出現(xiàn)會(huì)導(dǎo)致這三個(gè)問(wèn)題頻頻發(fā)生,。

那么聰明的你一定會(huì)問(wèn)了,,我們應(yīng)該如何去控制呢?(不問(wèn)的都拉出去彈雞兒)

一個(gè)一個(gè)來(lái):

可見(jiàn)性:

volatile關(guān)鍵字:通過(guò)volatile關(guān)鍵字修飾內(nèi)存中的變量,,該變量在線程之間共享

其實(shí)對(duì)于可見(jiàn)性而言,,無(wú)論是普通變量還是volatile變量都是如此,區(qū)別在于:volatile的特殊規(guī)則保證了volatile變量值修改后的新值立刻同步到主內(nèi)存,,每次使用volatile變量前立即從主內(nèi)存中刷新,,因此volatile保證了多線程之間的操作變量的可見(jiàn)性,而普通變量則不能保證這一點(diǎn),。

但是volatile只是對(duì)關(guān)鍵字進(jìn)行了修飾,,保證了其可見(jiàn)性,而對(duì)于線程的有序性和變量的原子性,,volatile根本沒(méi)有什么卵用,,也就是什么意思呢?

private static volatile int volatileCount = 0; private static void volatileCount() { for (int i = 0; i <>10; i++) { Executors.newFixedThreadPool(3).execute(() -> { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println('volatile count: ' + ++volatileCount); }); } }

代碼中的volatile,,加與不加,,沒(méi)多少區(qū)別。
因?yàn)関olatile只能保證其變量的可見(jiàn)性,。但是每個(gè)線程啥時(shí)候開(kāi)始跑,,我們根本不知道。當(dāng)A線程訪問(wèn)到volatileCount = 1時(shí),,并且開(kāi)始執(zhí)行時(shí),,如果B線程此時(shí)也訪問(wèn)到了,,他也一樣會(huì)執(zhí)行,雖然讀取volatileCount時(shí),,我們都能保證他是最新的,,但是我們不能保證,當(dāng)A線程在操作的時(shí)候,,B線程不能進(jìn)去插一腳,。

原子性:
java.util.concurrent.atomic,原子類了解一下,?
在java中,,我們知道++操作實(shí)際上并不是線程安全的,為了保證線程間的變量原子性,,java引入了atomic類,。它的作用就是保證,使用的變量,,一定是原子性的,。
代碼咱看一下:

private static AtomicInteger atomicCount = new AtomicInteger(0); private static void atomicCount() { for (int i = 0; i <>10; i++) { Executors.newFixedThreadPool(3).execute(() -> { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //atomicCount.incrementAndGet()方法的意思是讓其自增 1,等同于++ System.out.println('atomic count: ' + atomicCount.incrementAndGet()); }); } } // atomic count: 5 // atomic count: 1 // atomic count: 3 // atomic count: 2 // atomic count: 8 // atomic count: 10 // atomic count: 4 // atomic count: 6 // atomic count: 7 // atomic count: 9

結(jié)果也放在下面了,,可見(jiàn),,我們保證了它的唯一性,他是一定會(huì)自增到10的,。說(shuō)白了,,就是緩存鎖機(jī)制。
關(guān)于緩存鎖的機(jī)制,,下面有一個(gè)官方解釋,,可以學(xué)習(xí)一下:

緩存鎖是指通過(guò)鎖住CPU緩存,在CPU緩存區(qū)實(shí)現(xiàn)共享變量的原子性操作,。
如果緩存在處理器的緩存行中,,內(nèi)存區(qū)域在LOCK操作期間被鎖定,當(dāng)它執(zhí)行鎖操作,,回寫主內(nèi)存時(shí),,處理器不在總線鎖上聲言LOCK#信號(hào),而是修改內(nèi)部?jī)?nèi)存地址,,并允許它的緩存一致性機(jī)制來(lái)保證操作的原子性。因?yàn)榫彺嬉恢滦詸C(jī)制會(huì)阻止同時(shí)修改被兩個(gè)以上處理器緩存的內(nèi)存區(qū)域數(shù)據(jù),,當(dāng)其他處理器回寫已被鎖定的緩存行的數(shù)據(jù)時(shí)會(huì)起緩存行無(wú)效,。
緩存鎖使用的是比較并交換策略(Compare And Swap簡(jiǎn)稱CAS),CAS操作需要輸入兩個(gè)數(shù)值,,一個(gè)舊值(期望操作前的值)和一個(gè)新值,,在操作期間先比較下舊值有沒(méi)有發(fā)生變化,,如果沒(méi)有發(fā)生變化,才交換成新值,,發(fā)生了變化則不交換,。

這段話也解釋了為什么雖然我們不能保證其有序性,但是,,我們依然能正常的自增到10,。

有序性:
synchronized,日常用的最多的東西,,當(dāng)使用synchronized關(guān)鍵字時(shí),,只能有一個(gè)線程執(zhí)行直到執(zhí)行完成后或異常,才會(huì)釋放鎖,。所以可以保證synchronized代碼塊或方法只會(huì)有一個(gè)線程執(zhí)行,,保障了程序的有序性。

private static void synchronizedCount() { for (int i = 0; i <>10; i++) { Executors.newFixedThreadPool(3).execute(->() { @Override public void run() { synchronized (MyClass.class) { // 通過(guò)synchronized關(guān)鍵字來(lái)保證線程之間的有序性 System.out.println('synchronized count: ' + ++synchronizedCount); } } }); } }

結(jié)果看上去很美好,,有序,,且從1到10,一個(gè)不差,。
但是,,synchronized能不能保證原子性和可見(jiàn)性呢?還記得單例的DCL寫法么,?

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

如果不加volatile會(huì)有什么問(wèn)題呢,?
java內(nèi)存模型(jmm)并不限制處理器重排序,在執(zhí)行instance=new Singleton(),;時(shí),,并不是原子語(yǔ)句,實(shí)際是包括了下面三大步驟:
1.為對(duì)象分配內(nèi)存
2.初始化實(shí)例對(duì)象
3.把引用instance指向分配的內(nèi)存空間
這個(gè)三個(gè)步驟并不能保證按序執(zhí)行,,處理器會(huì)進(jìn)行指令重排序優(yōu)化,,存在這樣的情況:
優(yōu)化重排后執(zhí)行順序?yàn)椋?,3,2, 這樣在線程1執(zhí)行到3時(shí),instance已經(jīng)不為null了,,線程2此時(shí)判斷instance!=null,,則直接返回instance引用,但現(xiàn)在實(shí)例對(duì)象還沒(méi)有初始化完畢,,此時(shí)線程2使用instance可能會(huì)造成程序崩潰,。
所以說(shuō),實(shí)際上synchronized只是保證了其有序性,,并沒(méi)有辦法保證其原子性,,而其可見(jiàn)性,是依靠java的內(nèi)存模型來(lái)保證的。

OK,,基本說(shuō)清,,就此打住,老少爺們們,,咱下期再見(jiàn),。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多