<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ā)編程

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

    從這一節(jié)開始正式進(jìn)入并發(fā)容器的部分,來看看JDK 6帶來了哪些并發(fā)容器。

    在JDK 1.4以下只有Vector和Hashtable是線程安全的集合(也稱并發(fā)容器,Collections.synchronized*系列也可以看作是線程安全的實(shí)現(xiàn))。從JDK 5開始增加了線程安全的Map接口ConcurrentMap和線程安全的隊(duì)列BlockingQueue(盡管Queue也是同時(shí)期引入的新的集合,但是規(guī)范并沒有規(guī)定一定是線程安全的,事實(shí)上一些實(shí)現(xiàn)也不是線程安全的,比如PriorityQueue、ArrayDeque、LinkedList等,在Queue章節(jié)中會(huì)具體討論這些隊(duì)列的結(jié)構(gòu)圖和實(shí)現(xiàn))。

     

    在介紹ConcurrencyMap之前先來回顧下Map的體系結(jié)構(gòu)。下圖描述了Map的體系結(jié)構(gòu),其中藍(lán)色字體的是JDK 5以后新增的并發(fā)容器。

    image

    針對(duì)上圖有以下幾點(diǎn)說明:

    1. Hashtable是JDK 5之前Map唯一線程安全的內(nèi)置實(shí)現(xiàn)(Collections.synchronizedMap不算)。特別說明的是Hashtable的t是小寫的(不知道為啥),Hashtable繼承的是Dictionary(Hashtable是其唯一公開的子類),并不繼承AbstractMap或者HashMap。盡管Hashtable和HashMap的結(jié)構(gòu)非常類似,但是他們之間并沒有多大聯(lián)系。
    2. ConcurrentHashMap是HashMap的線程安全版本,ConcurrentSkipListMap是TreeMap的線程安全版本。
    3. 最終可用的線程安全版本Map實(shí)現(xiàn)是ConcurrentHashMap/ConcurrentSkipListMap/Hashtable/Properties四個(gè),但是Hashtable是過時(shí)的類庫(kù),因此如果可以的應(yīng)該盡可能的使用ConcurrentHashMap和ConcurrentSkipListMap。

     

    回到正題來,這個(gè)小節(jié)主要介紹ConcurrentHashMap的API以及應(yīng)用,下一節(jié)才開始將原理和分析。

    ConcurrentMap API

    除了實(shí)現(xiàn)Map接口里面對(duì)象的方法外,ConcurrentHashMap還實(shí)現(xiàn)了ConcurrentMap里面的四個(gè)方法。

     

    V putIfAbsent(K key,V value)

    如果不存在key對(duì)應(yīng)的值,則將value以key加入Map,否則返回key對(duì)應(yīng)的舊值。這個(gè)等價(jià)于清單1 的操作:

    清單1 putIfAbsent的等價(jià)操作

    if (!map.containsKey(key))
       return map.put(key, value);
    else
       return map.get(key);

    在前面的章節(jié)中提到過,連續(xù)兩個(gè)或多個(gè)原子操作的序列并不一定是原子操作。比如上面的操作即使在Hashtable中也不是原子操作。而putIfAbsent就是一個(gè)線程安全版本的操作的。

    有些人喜歡用這種功能來實(shí)現(xiàn)單例模式,例如清單2。

    清單2 一種單例模式的實(shí)現(xiàn)

    package xylz.study.concurrency;

    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ConcurrentMap;

    public class ConcurrentDemo1 {

        private static final ConcurrentMap<String, ConcurrentDemo1> map = new ConcurrentHashMap<String, ConcurrentDemo1>();
        private static ConcurrentDemo1 instance;
        public static ConcurrentDemo1 getInstance() {
            if (instance == null) {

                map.putIfAbsent("INSTANCE", new ConcurrentDemo1());

                instance = map.get("INSTANCE");
            }
            return instance;
        }

        private ConcurrentDemo1() {
        }

    }

    當(dāng)然這里只是一個(gè)操作的例子,實(shí)際上在單例模式文章中有很多的實(shí)現(xiàn)和比較。清單2 在存在大量單例的情況下可能有用,實(shí)際情況下很少用于單例模式。但是這個(gè)方法避免了向Map中的同一個(gè)Key提交多個(gè)結(jié)果的可能,有時(shí)候在去掉重復(fù)記錄上很有用(如果記錄的格式比較固定的話)。

     

    boolean remove(Object key,Object value)

    只有目前將鍵的條目映射到給定值時(shí),才移除該鍵的條目。這等價(jià)于清單3 的操作。

    清單3 remove(Object,Object)的等價(jià)操作

    if (map.containsKey(key) && map.get(key).equals(value)) {
       map.remove(key);
       return true;
    }
    return false;

    由于集合類通常比較的hashCode和equals方法,而這兩個(gè)方法是在Object對(duì)象里面,因此兩個(gè)對(duì)象如果hashCode一致,并且覆蓋了equals方法后也一致,那么這兩個(gè)對(duì)象在集合類里面就是“相同”的,不管是否是同一個(gè)對(duì)象或者同一類型的對(duì)象。也就是說只要key1.hashCode()==key2.hashCode() && key1.equals(key2),那么key1和key2在集合類里面就認(rèn)為是一致,哪怕他們的Class類型不一致也沒關(guān)系,所以在很多集合類里面允許通過Object來類型來比較(或者定位)。比如說Map盡管添加的時(shí)候只能通過制定的類型<K,V>,但是刪除的時(shí)候卻允許通過一個(gè)Object來操作,而不必是K類型。

    既然Map里面有一個(gè)remove(Object)方法,為什么ConcurrentMap還需要remove(Object,Object)方法呢?這是因?yàn)楸M管Map里面的key沒有變化,但是value可能已經(jīng)被其他線程修改了,如果修改后的值是我們期望的,那么我們就不能拿一個(gè)key來刪除此值,盡管我們的期望值是刪除此key對(duì)于的舊值。

    這種特性在原子操作章節(jié)的AtomicMarkableReferenceAtomicStampedReference里面介紹過。

     

    boolean replace(K key,V oldValue,V newValue)

    只有目前將鍵的條目映射到給定值時(shí),才替換該鍵的條目。這等價(jià)于清單4 的操作。

    清單4 replace(K,V,V)的等價(jià)操作

    if (map.containsKey(key) && map.get(key).equals(oldValue)) {
       map.put(key, newValue);
       return true;
    }
    return false;

     

    V replace(K key,V value)

    只有當(dāng)前鍵存在的時(shí)候更新此鍵對(duì)于的值。這等價(jià)于清單5 的操作。

    清單5 replace(K,V)的等價(jià)操作

    if (map.containsKey(key)) {
       return map.put(key, value);
    }
    return null;

    replace(K,V,V)相比replace(K,V)而言,就是增加了匹配oldValue的操作。

     

    其實(shí)這4個(gè)擴(kuò)展方法,是ConcurrentMap附送的四個(gè)操作,其實(shí)我們更關(guān)心的是Map本身的操作。當(dāng)然如果沒有這4個(gè)方法,要完成類似的功能我們可能需要額外的鎖,所以有總比沒有要好。比如清單6,如果沒有putIfAbsent內(nèi)置的方法,我們?nèi)绻瓿纱瞬僮骶托枰耆i住整個(gè)Map,這樣就大大降低了ConcurrentMap的并發(fā)性。這在下一節(jié)中有詳細(xì)的分析和討論。

    清單6 putIfAbsent的外部實(shí)現(xiàn)

    public V putIfAbsent(K key, V value) {
        synchronized (map) {
            if (!map.containsKey(key)) return map.put(key, value);
            return map.get(key);
        }
    }

     

    參考資料:

     



    ©2009-2014 IMXYLZ |求賢若渴
    posted on 2010-07-19 15:25 imxylz 閱讀(24650) 評(píng)論(8)  編輯  收藏 所屬分類: Java Concurrency

    評(píng)論

    # re: 深入淺出 Java Concurrency (16): 并發(fā)容器 part 1 ConcurrentMap (1)[未登錄] 2010-07-19 18:05 denis
    uml圖很漂亮,有點(diǎn)rational rose風(fēng)格,但是好像又有點(diǎn)區(qū)別。請(qǐng)問您用的uml軟件是?  回復(fù)  更多評(píng)論
      

    # re: 深入淺出 Java Concurrency (16): 并發(fā)容器 part 1 ConcurrentMap (1) 2010-07-19 18:12 xylz
    @denis
    Enterprise Architect 7.5  回復(fù)  更多評(píng)論
      

    # re: 深入淺出 Java Concurrency (16): 并發(fā)容器 part 1 ConcurrentMap (1)[未登錄] 2010-07-19 18:14 denis
    @xylz
    唉,果然,可惜要破解。  回復(fù)  更多評(píng)論
      

    # re: 深入淺出 Java Concurrency (16): 并發(fā)容器 part 1 ConcurrentMap (1) 2011-01-03 23:57 fordybeach
    map.put第一次返回的是null
    所以map.putIfAbsent第一次也是返回的null,那個(gè)單例模式第一次就返回的是null  回復(fù)  更多評(píng)論
      

    # re: 深入淺出 Java Concurrency (16): 并發(fā)容器 part 1 ConcurrentMap (1) 2011-01-04 13:02 xylz
    @fordybeach
    已經(jīng)改正過來了,多謝多謝,你太仔細(xì)了  回復(fù)  更多評(píng)論
      

    # re: 深入淺出 Java Concurrency (16): 并發(fā)容器 part 1 ConcurrentMap (1) 2012-08-02 11:50 殘陽(yáng)
    2啊,因?yàn)镠ashtable是一個(gè)單詞啊,并非hash和table的聯(lián)合。。。  回復(fù)  更多評(píng)論
      

    # re: 深入淺出 Java Concurrency (16): 并發(fā)容器 part 1 ConcurrentMap (1) 2013-03-26 14:22 kkkkkkkkk
    Hashtable是集成Ojbect,lz看清楚了再寫的,不要誤導(dǎo)人的。  回復(fù)  更多評(píng)論
      

    # re: 深入淺出 Java Concurrency (16): 并發(fā)容器 part 1 ConcurrentMap (1) 2014-12-16 10:27 卓洛
    @kkkkkkkkk
    是你沒看清楚吧  回復(fù)  更多評(píng)論
      


    ©2009-2014 IMXYLZ
    主站蜘蛛池模板: 国产精品成人免费视频网站京东| 国产免费久久精品丫丫| 免费人成视频在线观看网站| 一本色道久久综合亚洲精品| 污污污视频在线免费观看| 亚洲国产V高清在线观看| 亚洲成av人片天堂网无码】| 大学生一级特黄的免费大片视频| 国产 亚洲 中文在线 字幕| 最近2019中文字幕mv免费看 | 一本天堂ⅴ无码亚洲道久久| 免费可以在线看A∨网站| 国产亚洲精品影视在线| 成人午夜视频免费| 国产亚洲午夜精品| 久久影视综合亚洲| 国产一区二区三区免费| 亚洲专区先锋影音| 无码人妻久久一区二区三区免费丨| 中文日韩亚洲欧美制服| 国产精品美女自在线观看免费| 精品女同一区二区三区免费播放| 精品国产香蕉伊思人在线在线亚洲一区二区| 久青草国产免费观看| 精品久久久久久亚洲| 国产h肉在线视频免费观看| 精品丝袜国产自在线拍亚洲| 免费激情视频网站| 一级毛片免费毛片毛片| 亚洲人成依人成综合网| 成人免费视频软件网站| WWW国产成人免费观看视频| 久久精品国产亚洲AV无码娇色| 无码高潮少妇毛多水多水免费| 四虎精品免费永久免费视频| 亚洲精品无码av人在线观看| 免费能直接在线观看黄的视频 | 成人免费午夜在线观看| 一级毛片a免费播放王色电影| 亚洲国产精品久久久久婷婷软件| 成人免费a级毛片|