乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      無鎖同步

       月冷星河 2016-07-21

      1、概要

      本文是無鎖同步系列文章的第二篇,主要探討JAVA中的原子操作,以及如何進(jìn)行無鎖同步。

      關(guān)于JAVA中的原子操作,我們很容易想到的是Volatile變量、java.util.concurrent.atomic包和JVM提供的CAS操作。

      2、Volatile

      1)Volatile變量不具有原子性

      Volatile變量具有一種可見性,該特性能保證不同線程甚至處理器核心在對(duì)這種類型的變量在讀取的時(shí)候能讀到最新的值。但Volatile變量不提供原子操作的保證。

      下面我們給出一個(gè)例子:

      1 public class test { 2 3 volatile static int someValue; 4 5 public static void main(String[] args) { 6 someValue = 1; 7 int b = someValue; 8 } 9 10 }

      在這個(gè)例子中,我們對(duì)一個(gè)int類型的volatile變量進(jìn)行寫和讀,在這種場(chǎng)景下volatile變量的讀和寫操作是原子的(注意:這里指是讀操作和寫操作分別是原子的),并且jvm會(huì)為我們保證happens-before語義(即會(huì)保證寫操作在讀操作之前發(fā)生,其實(shí)jvm給我們提供的不單止是happens-before,具體詳情我們?cè)诒鞠盗械南乱黄┪脑倬唧w介紹)。我們可以利用這個(gè)特性完成一小部分線程同步的需求。但是我們需要注意下面這種情況。

      1 public class test {2 3 volatile static int someValue;4 5 public static void main(String[] args) {6 someValue++;7 }8 9 }

      在這里,我們把讀和寫操作改成一個(gè)自增操作,那么這個(gè)自增操作是不是原子的呢?

      答案是否定的。

      自增操作其本質(zhì)是

      1 int tmp = someValue;2 tmp += 1;3 someValue = tmp;

      這里包含讀、加、寫3個(gè)操作。對(duì)于int類型來說,java保證這里面的讀和寫操作中是原子的,但不保證它們加在一起仍然是原子的。

      也正是由于這個(gè)特性,單獨(dú)使用volatile變量還不足以實(shí)現(xiàn)計(jì)數(shù)器等包含計(jì)算的需求。但是如果使用恰當(dāng),這種變量將為線程間的同步帶來無可比擬的性能提升。

      2)Volatile變量如何保證可見性

      我們知道現(xiàn)代的CPU為了優(yōu)化性能,計(jì)算時(shí)一般不與內(nèi)存直接交互。一般先把數(shù)據(jù)從內(nèi)存讀取到CPU內(nèi)部緩存再進(jìn)行操作。而不同線程可能由不同的CPU內(nèi)核執(zhí)行,很可能會(huì)導(dǎo)致某變量在不同的處理器中保存著2個(gè)不同副本的情況,導(dǎo)致數(shù)據(jù)不一致,產(chǎn)生意料之外的結(jié)果。那么java是怎么保證volatile變量在所有線程中的數(shù)據(jù)都是一致的呢?

      若對(duì)一個(gè)Volatile變量進(jìn)行賦值,編譯后除了生成賦值字節(jié)碼外,還會(huì)生成一個(gè)lock指令。該指令是CPU提供的,能實(shí)現(xiàn)下面2個(gè)功能:

      1. 將CPU當(dāng)前緩存行內(nèi)的新數(shù)據(jù)寫入內(nèi)存
      2. 將其它CPU核心里包含本變量的緩存行無效化,以強(qiáng)制下次讀取時(shí)到內(nèi)存中讀取

      上述過程基于CPU內(nèi)部的一套緩存協(xié)議。具體可以查閱相關(guān)文檔。

      2、java.util.concurrent.atomic包和CAS

      對(duì)比volatile變量,atomic包給我們提供了AtomicInteger、AtomicLong、AtomicBoolean等類,提供了一系列原子操作。

      AtomicIntegerGet/Set

      下面我們進(jìn)入AtomicInteger類探秘,看看它是如何實(shí)現(xiàn)原子讀寫的。(下文使用的源碼均來自JDK7)

      1 private volatile int value; 2 3 /** 4 * Gets the current value. 5 * 6 * @return the current value 7 */ 8 public final int get { 9 return value;10 }11 12 /**13 * Sets to the given value.14 *15 * @param newValue the new value16 */17 public final void set(int newValue) {18 value = newValue;19 }

      沒有錯(cuò),就是利用我們上面提到的volatile實(shí)現(xiàn)的。

      compareAndSet(int expect, int update)和weakCompareAndSet(int expect, int update)

      這就是著名的CAS(compare and set)接口。

      對(duì)比變量的值和expect是否相等,如果相等則將變量的值更新為update。參考第一篇,我們可以根據(jù)這個(gè)特性實(shí)現(xiàn)一些無鎖數(shù)據(jù)結(jié)構(gòu)。事實(shí)上,JDK8中的java.util.concurrent包有不少數(shù)據(jù)結(jié)構(gòu)被使用CAS優(yōu)化,其中最著名的就是ConcurrentHashMap。

      而要說到weak版本的CAS接口有什么特別之處,它的注釋說明它會(huì)'fail spuriously',但是其源碼卻是一模一樣的。

      1 /** 2 * Atomically sets the value to the given updated value 3 * if the current value {@code ==} the expected value. 4 * 5 * @param expect the expected value 6 * @param update the new value 7 * @return true if successful. False return indicates that 8 * the actual value was not equal to the expected value. 9 */10 public final boolean compareAndSet(int expect, int update) {11 return unsafe.compareAndSwapInt(this, valueOffset, expect, update);12 }13 14 /**15 * Atomically sets the value to the given updated value16 * if the current value {@code ==} the expected value.17 *18 *

      May fail spuriously19 * and does not provide ordering guarantees, so is only rarely an20 * appropriate alternative to {@code compareAndSet}.21 *22 * @param expect the expected value23 * @param update the new value24 * @return true if successful.25 */26 public final boolean weakCompareAndSet(int expect, int update) {27 return unsafe.compareAndSwapInt(this, valueOffset, expect, update);28 }

      證明SUN JDK 7沒有安裝標(biāo)準(zhǔn)實(shí)現(xiàn)weak版本的接口,但是我們無法保證以后的JDK是如何實(shí)現(xiàn)的。因此,無論何時(shí),我們都不應(yīng)假定weak版本的CAS操作和非weak版本具有完全一致的行為。

      其他常用接口

      int addAndGet(int delta) 以原子方式將給定值與當(dāng)前值相加。 功能等價(jià)于i=i+delta。

      int getAndAdd(int delta) 以原子方式將給定值與當(dāng)前值相加。 功能等價(jià)于{int tmp=i;i+=delta;return tmp;}。

      int getAndIncrement 以原子方式將當(dāng)前值加 1。 功能等價(jià)于i++。

      int decrementAndGet 以原子方式將當(dāng)前值減 1。 功能等價(jià)于--i。

      int getAndDecrement 以原子方式將當(dāng)前值減 1。 功能等價(jià)于i--。

      int getAndSet(int newValue) 以原子方式設(shè)置為給定值,并返回舊值。 功能等價(jià)于{int tmp=i;i=newValue;return tmp;}。

      int incrementAndGet 以原子方式將當(dāng)前值加 1。 功能等價(jià)于++i。

        本站是提供個(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)論公約

        類似文章 更多