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

分享

Java 多線程三大核心

 太極混元天尊 2018-06-10

原子性

Java 的原子性就和數(shù)據(jù)庫(kù)事物的原子性差不多,,一個(gè)操作中要么全部執(zhí)行成功或者失敗,。

JMM 只是保證了基本的原子性,,但類似于 i++ 之類的操作,,看似是原子操作,,其實(shí)里面涉及到:

  • 獲取 i 的值,。
  • 自增,。
  • 再賦值給 i。

這三步操作,,所以想要實(shí)現(xiàn) i++ 這樣的原子操作就需要用到 synchronize 或者是 lock 進(jìn)行加鎖處理,。

如果是基礎(chǔ)類的自增操作可以使用 AtomicInteger 這樣的原子類來(lái)實(shí)現(xiàn)(其本質(zhì)是利用了 CPU 級(jí)別的 的 CAS 指令來(lái)完成的)。

其中用的最多的方法就是: incrementAndGet() 以原子的方式自增。 源碼如下:

public final long incrementAndGet() { for (;;) { long current = get(); long next = current + 1; if (compareAndSet(current, next)) return next; } }

首先是獲得當(dāng)前的值,,然后自增 +1,。接著則是最核心的 compareAndSet() 來(lái)進(jìn)行原子更新。

public final boolean compareAndSet(long expect, long update) { return unsafe.compareAndSwapLong(this, valueOffset, expect, update); }

其邏輯就是判斷當(dāng)前的值是否被更新過(guò),,是否等于 current,,如果等于就說(shuō)明沒(méi)有更新過(guò)然后將當(dāng)前的值更新為 next,如果不等于則返回false 進(jìn)入循環(huán),,直到更新成功為止,。

還有其中的 get() 方法也很關(guān)鍵,返回的是當(dāng)前的值,,當(dāng)前值用了 volatile 關(guān)鍵詞修飾,,保證了內(nèi)存可見(jiàn)性。

private volatile int value;

可見(jiàn)性

現(xiàn)代計(jì)算機(jī)中,,由于 CPU 直接從主內(nèi)存中讀取數(shù)據(jù)的效率不高,,所以都會(huì)對(duì)應(yīng)的 CPU 高速緩存,先將主內(nèi)存中的數(shù)據(jù)讀取到緩存中,,線程修改數(shù)據(jù)之后首先更新到緩存,,之后才會(huì)更新到主內(nèi)存。如果此時(shí)還沒(méi)有將數(shù)據(jù)更新到主內(nèi)存其他的線程此時(shí)來(lái)讀取就是修改之前的數(shù)據(jù),。

Java 多線程三大核心

如上圖所示,。

volatile 關(guān)鍵字就是用于保證內(nèi)存可見(jiàn)性,當(dāng)線程A更新了 volatile 修飾的變量時(shí),,它會(huì)立即刷新到主線程,,并且將其余緩存中該變量的值清空,導(dǎo)致其余線程只能去主內(nèi)存讀取最新值,。

使用 volatile 關(guān)鍵詞修飾的變量每次讀取都會(huì)得到最新的數(shù)據(jù),,不管哪個(gè)線程對(duì)這個(gè)變量的修改都會(huì)立即刷新到主內(nèi)存。

synchronize和加鎖也能能保證可見(jiàn)性,,實(shí)現(xiàn)原理就是在釋放鎖之前其余線程是訪問(wèn)不到這個(gè)共享變量的,。但是和 volatile 相比開(kāi)銷(xiāo)較大。

順序性

以下這段代碼:

int a = 100 ; //1int b = 200 ; //2int c = a + b ; //3

正常情況下的執(zhí)行順序應(yīng)該是 1>>2>>3,。但是有時(shí) JVM 為了提高整體的效率會(huì)進(jìn)行指令重排導(dǎo)致執(zhí)行的順序可能是 2>>1>>3,。但是 JVM 也不能是什么都進(jìn)行重排,是在保證最終結(jié)果和代碼順序執(zhí)行結(jié)果一致的情況下才可能進(jìn)行重排,。

重排在單線程中不會(huì)出現(xiàn)問(wèn)題,,但在多線程中會(huì)出現(xiàn)數(shù)據(jù)不一致的問(wèn)題。

Java 中可以使用 volatile 來(lái)保證順序性,,synchronize 和 lock 也可以來(lái)保證有序性,,和保證原子性的方式一樣,,通過(guò)同一段時(shí)間只能一個(gè)線程訪問(wèn)來(lái)實(shí)現(xiàn)的。

除了通過(guò) volatile 關(guān)鍵字顯式的保證順序之外,, JVM 還通過(guò) happen-before 原則來(lái)隱式的保證順序性,。

其中有一條就是適用于 volatile 關(guān)鍵字的,針對(duì)于 volatile 關(guān)鍵字的寫(xiě)操作肯定是在讀操作之前,,也就是說(shuō)讀取的值肯定是最新的,。

volatile 的應(yīng)用

雙重檢查鎖的單例模式

可以用 volatile 實(shí)現(xiàn)一個(gè)雙重檢查鎖的單例模式:

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

這里的 volatile 關(guān)鍵字主要是為了防止指令重排。 如果不用 volatile ,,singleton = new Singleton();,,這段代碼其實(shí)是分為三步:

  • 分配內(nèi)存空間。(1)
  • 初始化對(duì)象,。(2)
  • 將 singleton 對(duì)象指向分配的內(nèi)存地址,。(3)

加上 volatile 是為了讓以上的三步操作順序執(zhí)行,反之有可能第二步在第三步之前被執(zhí)行就有可能某個(gè)線程拿到的單例對(duì)象是還沒(méi)有初始化的,,以致于報(bào)錯(cuò)。

控制停止線程的標(biāo)記

private volatile boolean flag ;private void run(){ new Thread(new Runnable(){ if(flag){ doSomeThing(); } });}private void stop(){ flag = false ;}

這里如果沒(méi)有用 volatile 來(lái)修飾 flag ,,就有可能其中一個(gè)線程調(diào)用了 stop()方法修改了 flag 的值并不會(huì)立即刷新到主內(nèi)存中,,導(dǎo)致這個(gè)循環(huán)并不會(huì)立即停止。

這里主要利用的是 volatile 的內(nèi)存可見(jiàn)性,。

總結(jié)一下:

  • volatile 關(guān)鍵字只能保證可見(jiàn)性,,順序性,

    不能保證原子性

    ,。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(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)論公約

    類似文章 更多