<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    xylz,imxylz

    關(guān)注后端架構(gòu)、中間件、分布式和并發(fā)編程

       :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      111 隨筆 :: 10 文章 :: 2680 評論 :: 0 Trackbacks

    從相對簡單的Atomic入手(java.util.concurrent是基于Queue的并發(fā)包,而Queue,很多情況下使用到了Atomic操作,因此首先從這里開始)。很多情況下我們只是需要一個簡單的、高效的、線程安全的遞增遞減方案。注意,這里有三個條件:簡單,意味著程序員盡可能少的操作底層或者實現(xiàn)起來要比較容易;高效意味著耗用資源要少,程序處理速度要快;線程安全也非常重要,這個在多線程下能保證數(shù)據(jù)的正確性。這三個條件看起來比較簡單,但是實現(xiàn)起來卻難以令人滿意。

    通常情況下,在Java里面,++i或者--i不是線程安全的,這里面有三個獨立的操作:或者變量當前值,為該值+1/-1,然后寫回新的值。在沒有額外資源可以利用的情況下,只能使用加鎖才能保證讀-改-寫這三個操作時“原子性”的。

    Doug Lea在未將backport-util-concurrent合并到JSR 166里面來之前,是采用純Java實現(xiàn)的,于是不可避免的采用了synchronized關(guān)鍵字。

    public final synchronized void set(int newValue);

    public final synchronized int getAndSet(int newValue);

    public final synchronized int incrementAndGet();

    同時在變量上使用了volatile (后面會具體來講volatile到底是個什么東東)來保證get()的時候不用加鎖。盡管synchronized的代價還是很高的,但是在沒有JNI的手段下純Java語言還是不能實現(xiàn)此操作的。

    JSR 166提上日程后,backport-util-concurrent就合并到JDK 5.0里面了,在這里面重復使用了現(xiàn)代CPU的特性來降低鎖的消耗。后本章的最后小結(jié)中會談到這些原理和特性。在此之前先看看API的使用。

    一切從java.util.concurrent.atomic.AtomicInteger開始。

    int addAndGet(int delta)
              以原子方式將給定值與當前值相加。 實際上就是等于線程安全版本的i =i+delta操作。

    boolean compareAndSet(int expect, int update)
              如果當前值 == 預期值,則以原子方式將該值設置為給定的更新值。 如果成功就返回true,否則返回false,并且不修改原值。

    int decrementAndGet()
              以原子方式將當前值減 1。 相當于線程安全版本的--i操作。

    int get()
              獲取當前值。

    int getAndAdd(int delta)
              以原子方式將給定值與當前值相加。 相當于線程安全版本的t=i;i+=delta;return t;操作。

    int getAndDecrement()
              以原子方式將當前值減 1。 相當于線程安全版本的i--操作。

    int getAndIncrement()
              以原子方式將當前值加 1。 相當于線程安全版本的i++操作。

    int getAndSet(int newValue)
              以原子方式設置為給定值,并返回舊值。 相當于線程安全版本的t=i;i=newValue;return t;操作。

    int incrementAndGet()
              以原子方式將當前值加 1。 相當于線程安全版本的++i操作。 

    void lazySet(int newValue)
              最后設置為給定值。 延時設置變量值,這個等價于set()方法,但是由于字段是volatile類型的,因此次字段的修改會比普通字段(非volatile字段)有稍微的性能延時(盡管可以忽略),所以如果不是想立即讀取設置的新值,允許在“后臺”修改值,那么此方法就很有用。如果還是難以理解,這里就類似于啟動一個后臺線程如執(zhí)行修改新值的任務,原線程就不等待修改結(jié)果立即返回(這種解釋其實是不正確的,但是可以這么理解)。

    void set(int newValue)
              設置為給定值。 直接修改原始值,也就是i=newValue操作。

    boolean weakCompareAndSet(int expect, int update)
              如果當前值 == 預期值,則以原子方式將該設置為給定的更新值。JSR規(guī)范中說:以原子方式讀取和有條件地寫入變量但 創(chuàng)建任何 happen-before 排序,因此不提供與除 weakCompareAndSet 目標外任何變量以前或后續(xù)讀取或?qū)懭氩僮饔嘘P(guān)的任何保證。大意就是說調(diào)用weakCompareAndSet時并不能保證不存在happen-before的發(fā)生(也就是可能存在指令重排序?qū)е麓瞬僮魇。?。但是從Java源碼來看,其實此方法并沒有實現(xiàn)JSR規(guī)范的要求,最后效果和compareAndSet是等效的,都調(diào)用了unsafe.compareAndSwapInt()完成操作。


    下面的代碼是一個測試樣例,為了省事就寫在一個方法里面來了。
    package xylz.study.concurrency.atomic;

    import java.util.concurrent.atomic.AtomicInteger;

    import org.junit.Test;

    import static org.junit.Assert.*;

    public class AtomicIntegerTest {

        @Test
        
    public void testAll() throws InterruptedException{
            
    final AtomicInteger value = new AtomicInteger(10);
            assertEquals(value.compareAndSet(
    12), false);
            assertEquals(value.get(), 
    10);
            assertTrue(value.compareAndSet(
    103));
            assertEquals(value.get(), 
    3);
            value.set(
    0);
            
    //
            assertEquals(value.incrementAndGet(), 1);
            assertEquals(value.getAndAdd(
    2),1);
            assertEquals(value.getAndSet(
    5),3);
            assertEquals(value.get(),
    5);
            
    //
            final int threadSize = 10;
            Thread[] ts 
    = new Thread[threadSize];
            
    for (int i = 0; i < threadSize; i++{
                ts[i] 
    = new Thread() {
                    
    public void run() {
                        value.incrementAndGet();
                    }

                }
    ;
            }

            
    //
            for(Thread t:ts) {
                t.start();
            }

            
    for(Thread t:ts) {
                t.join();
            }

            
    //
            assertEquals(value.get(), 5+threadSize);
        }


    }


     由于這里例子比較簡單,這里就不做過多介紹了。
    AtomicInteger和AtomicLong、AtomicBoolean、AtomicReference差不多,這里就不介紹了。在下一篇中就介紹下數(shù)組、字段等其他方面的原子操作。
     參考資料:
    (1)http://stackoverflow.com/questions/2443239/java-atomicinteger-what-are-the-differences-between-compareandset-and-weakcompar
    (2)http://stackoverflow.com/questions/1468007/atomicinteger-lazyset-and-set


    ©2009-2014 IMXYLZ |求賢若渴
    posted on 2010-07-01 15:21 imxylz 閱讀(65853) 評論(2)  編輯  收藏 所屬分類: J2EE

    評論

    # re: 深入淺出 Java Concurrency (2): 原子操作 part 1 2014-09-13 16:44 柳qing
    AtomicInteger
    的所有操作,包括set,也是原子操作么?  回復  更多評論
      

    # 提供參考鏈接 2016-06-30 00:23 33

    lazySet參考鏈接:
    http://stackoverflow.com/questions/1468007/atomicinteger-lazyset-vs-set


    weakCompareAndSet參考鏈接:
    http://stackoverflow.com/questions/2443239/how-can-weakcompareandset-fail-spuriously-if-it-is-implemented-exactly-like-comp

      回復  更多評論
      


    ©2009-2014 IMXYLZ
    主站蜘蛛池模板: 亚洲午夜国产精品| 伊人久久大香线蕉免费视频| 亚洲人成在线免费观看| 亚洲粉嫩美白在线| 中国china体内裑精亚洲日本| 色天使色婷婷在线影院亚洲| 免费一级全黄少妇性色生活片| 一级毛片a免费播放王色电影| 在线观看黄片免费入口不卡| 亚洲成年人免费网站| 免费看的黄色大片| 亚洲精品成人无限看| 一区二区亚洲精品精华液 | 国产色在线|亚洲| 一区二区三区精品高清视频免费在线播放| 精品多毛少妇人妻AV免费久久| 羞羞漫画页面免费入口欢迎你| 国产91久久久久久久免费| 亚洲av综合av一区| 色偷偷噜噜噜亚洲男人| a级毛片黄免费a级毛片| 国产成人免费ā片在线观看| 亚洲国产美女精品久久久久∴| 亚洲一区免费视频| 免费av一区二区三区| 国偷自产一区二区免费视频 | 中文字幕无码免费久久9一区9| 免费福利视频导航| 免费高清资源黄网站在线观看| 国产成人亚洲综合无码精品| 日韩在线视频免费| 好爽好紧好大的免费视频国产| 亚洲天堂福利视频| 亚洲免费二区三区| 亚洲精品91在线| 91福利免费视频| 亚洲欧洲精品久久| 免费看片在线观看| 亚洲制服丝袜在线播放| 亚洲一区免费在线观看| 亚洲男女一区二区三区|