<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é)開(kāi)始介紹鎖里面的最后一個(gè)工具:讀寫(xiě)鎖(ReadWriteLock)。

    ReentrantLock 實(shí)現(xiàn)了標(biāo)準(zhǔn)的互斥操作,也就是一次只能有一個(gè)線(xiàn)程持有鎖,也即所謂獨(dú)占鎖的概念。前面的章節(jié)中一直在強(qiáng)調(diào)這個(gè)特點(diǎn)。顯然這個(gè)特點(diǎn)在一定程度上面減低了吞吐量,實(shí)際上獨(dú)占鎖是一種保守的鎖策略,在這種情況下任何“讀/讀”,“寫(xiě)/讀”,“寫(xiě)/寫(xiě)”操作都不能同時(shí)發(fā)生。但是同樣需要強(qiáng)調(diào)的一個(gè)概念是,鎖是有一定的開(kāi)銷(xiāo)的,當(dāng)并發(fā)比較大的時(shí)候,鎖的開(kāi)銷(xiāo)就比較客觀(guān)了。所以如果可能的話(huà)就盡量少用鎖,非要用鎖的話(huà)就嘗試看能否改造為讀寫(xiě)鎖。

    ReadWriteLock描述的是:一個(gè)資源能夠被多個(gè)讀線(xiàn)程訪(fǎng)問(wèn),或者被一個(gè)寫(xiě)線(xiàn)程訪(fǎng)問(wèn),但是不能同時(shí)存在讀寫(xiě)線(xiàn)程。也就是說(shuō)讀寫(xiě)鎖使用的場(chǎng)合是一個(gè)共享資源被大量讀取操作,而只有少量的寫(xiě)操作(修改數(shù)據(jù))。清單1描述了ReadWriteLock的API。

     清單1 ReadWriteLock 接口

    public interface ReadWriteLock {
        Lock readLock();
        Lock writeLock();
    }

    清單1描述的ReadWriteLock結(jié)構(gòu),這里需要說(shuō)明的是ReadWriteLock并不是Lock的子接口,只不過(guò)ReadWriteLock借助Lock來(lái)實(shí)現(xiàn)讀寫(xiě)兩個(gè)視角。在ReadWriteLock中每次讀取共享數(shù)據(jù)就需要讀取鎖,當(dāng)需要修改共享數(shù)據(jù)時(shí)就需要寫(xiě)入鎖。看起來(lái)好像是兩個(gè)鎖,但其實(shí)不盡然,在下一節(jié)中的分析中會(huì)解釋這點(diǎn)奧秘。

    在JDK 6里面ReadWriteLock的實(shí)現(xiàn)是ReentrantReadWriteLock。

    清單2 SimpleConcurrentMap

    package xylz.study.concurrency.lock;

    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;

    public class SimpleConcurrentMap<K, V> implements Map<K, V> {

        final ReadWriteLock lock = new ReentrantReadWriteLock();

        final Lock r = lock.readLock();

        final Lock w = lock.writeLock();

        final Map<K, V> map;

        public SimpleConcurrentMap(Map<K, V> map) {
            this.map = map;
            if (map == null) throw new NullPointerException();
        }

        public void clear() {
            w.lock();
            try {
                map.clear();
            } finally {
                w.unlock();
            }
        }

        public boolean containsKey(Object key) {
            r.lock();
            try {
                return map.containsKey(key);
            } finally {
                r.unlock();
            }
        }

        public boolean containsValue(Object value) {
            r.lock();
            try {
                return map.containsValue(value);
            } finally {
                r.unlock();
            }
        }

        public Set<java.util.Map.Entry<K, V>> entrySet() {
            throw new UnsupportedOperationException();
        }

        public V get(Object key) {
            r.lock();
            try {
                return map.get(key);
            } finally {
                r.unlock();
            }
        }

        public boolean isEmpty() {
            r.lock();
            try {
                return map.isEmpty();
            } finally {
                r.unlock();
            }
        }

        public Set<K> keySet() {
            r.lock();
            try {
                return new HashSet<K>(map.keySet());
            } finally {
                r.unlock();
            }
        }

        public V put(K key, V value) {
            w.lock();
            try {
                return map.put(key, value);
            } finally {
                w.unlock();
            }
        }

        public void putAll(Map<? extends K, ? extends V> m) {
            w.lock();
            try {
                map.putAll(m);
            } finally {
                w.unlock();
            }
        }

        public V remove(Object key) {
            w.lock();
            try {
                return map.remove(key);
            } finally {
                w.unlock();
            }
        }

        public int size() {
            r.lock();
            try {
                return map.size();
            } finally {
                r.unlock();
            }
        }

        public Collection<V> values() {
            r.lock();
            try {
                return new ArrayList<V>(map.values());
            } finally {
                r.unlock();
            }
        }

    }

    清單2描述的是用讀寫(xiě)鎖實(shí)現(xiàn)的一個(gè)線(xiàn)程安全的Map。其中需要特別說(shuō)明的是并沒(méi)有實(shí)現(xiàn)entrySet()方法,這是因?yàn)閷?shí)現(xiàn)這個(gè)方法比較復(fù)雜,在后面章節(jié)中講到ConcurrentHashMap的時(shí)候會(huì)具體談這些細(xì)節(jié)。另外這里keySet()和values()也沒(méi)有直接返回Map的視圖,而是一個(gè)映射原有元素的新視圖,其實(shí)這個(gè)entrySet()一樣,是為了保護(hù)原始Map的數(shù)據(jù)邏輯,防止不正確的修改導(dǎo)致原始Map發(fā)生數(shù)據(jù)錯(cuò)誤。特別說(shuō)明的是在沒(méi)有特別需求的情況下沒(méi)有必要按照清單2寫(xiě)一個(gè)線(xiàn)程安全的Map實(shí)現(xiàn),因?yàn)镃oncurrentHashMap已經(jīng)完成了此操作。

     

    ReadWriteLock需要嚴(yán)格區(qū)分讀寫(xiě)操作,如果讀操作使用了寫(xiě)入鎖,那么降低讀操作的吞吐量,如果寫(xiě)操作使用了讀取鎖,那么就可能發(fā)生數(shù)據(jù)錯(cuò)誤。

    另外ReentrantReadWriteLock還有以下幾個(gè)特性:

    • 公平性
      • 非公平鎖(默認(rèn)) 這個(gè)和獨(dú)占鎖的非公平性一樣,由于讀線(xiàn)程之間沒(méi)有鎖競(jìng)爭(zhēng),所以讀操作沒(méi)有公平性和非公平性,寫(xiě)操作時(shí),由于寫(xiě)操作可能立即獲取到鎖,所以會(huì)推遲一個(gè)或多個(gè)讀操作或者寫(xiě)操作。因此非公平鎖的吞吐量要高于公平鎖。
      • 公平鎖 利用AQS的CLH隊(duì)列,釋放當(dāng)前保持的鎖(讀鎖或者寫(xiě)鎖)時(shí),優(yōu)先為等待時(shí)間最長(zhǎng)的那個(gè)寫(xiě)線(xiàn)程分配寫(xiě)入鎖,當(dāng)前前提是寫(xiě)線(xiàn)程的等待時(shí)間要比所有讀線(xiàn)程的等待時(shí)間要長(zhǎng)。同樣一個(gè)線(xiàn)程持有寫(xiě)入鎖或者有一個(gè)寫(xiě)線(xiàn)程已經(jīng)在等待了,那么試圖獲取公平鎖的(非重入)所有線(xiàn)程(包括讀寫(xiě)線(xiàn)程)都將被阻塞,直到最先的寫(xiě)線(xiàn)程釋放鎖。如果讀線(xiàn)程的等待時(shí)間比寫(xiě)線(xiàn)程的等待時(shí)間還有長(zhǎng),那么一旦上一個(gè)寫(xiě)線(xiàn)程釋放鎖,這一組讀線(xiàn)程將獲取鎖。
    • 重入性
      • 讀寫(xiě)鎖允許讀線(xiàn)程和寫(xiě)線(xiàn)程按照請(qǐng)求鎖的順序重新獲取讀取鎖或者寫(xiě)入鎖。當(dāng)然了只有寫(xiě)線(xiàn)程釋放了鎖,讀線(xiàn)程才能獲取重入鎖。
      • 寫(xiě)線(xiàn)程獲取寫(xiě)入鎖后可以再次獲取讀取鎖,但是讀線(xiàn)程獲取讀取鎖后卻不能獲取寫(xiě)入鎖。
      • 另外讀寫(xiě)鎖最多支持65535個(gè)遞歸寫(xiě)入鎖和65535個(gè)遞歸讀取鎖。
    • 鎖降級(jí)
      • 寫(xiě)線(xiàn)程獲取寫(xiě)入鎖后可以獲取讀取鎖,然后釋放寫(xiě)入鎖,這樣就從寫(xiě)入鎖變成了讀取鎖,從而實(shí)現(xiàn)鎖降級(jí)的特性。
    • 鎖升級(jí)
      • 讀取鎖是不能直接升級(jí)為寫(xiě)入鎖的。因?yàn)楂@取一個(gè)寫(xiě)入鎖需要釋放所有讀取鎖,所以如果有兩個(gè)讀取鎖視圖獲取寫(xiě)入鎖而都不釋放讀取鎖時(shí)就會(huì)發(fā)生死鎖。
    • 鎖獲取中斷
      • 讀取鎖和寫(xiě)入鎖都支持獲取鎖期間被中斷。這個(gè)和獨(dú)占鎖一致。
    • 條件變量
      • 寫(xiě)入鎖提供了條件變量(Condition)的支持,這個(gè)和獨(dú)占鎖一致,但是讀取鎖卻不允許獲取條件變量,將得到一個(gè)UnsupportedOperationException異常。
    • 重入數(shù)
      • 讀取鎖和寫(xiě)入鎖的數(shù)量最大分別只能是65535(包括重入數(shù))。這在下節(jié)中有介紹。

    上面幾個(gè)特性對(duì)讀寫(xiě)鎖的理解很有幫助,而且也是必要的,另外在下一節(jié)中講ReadWriteLock的實(shí)現(xiàn)會(huì)用到這些知識(shí)的。

     

     



    ©2009-2014 IMXYLZ |求賢若渴
    posted on 2010-07-14 14:18 imxylz 閱讀(24267) 評(píng)論(4)  編輯  收藏 所屬分類(lèi): J2EE

    評(píng)論

    # re: 深入淺出 Java Concurrency (13): 鎖機(jī)制 part 8 讀寫(xiě)鎖 (ReentrantReadWriteLock) (1)[未登錄](méi) 2010-07-14 20:11 行云流水
    默默支持。。  回復(fù)  更多評(píng)論
      

    # re: 深入淺出 Java Concurrency (13): 鎖機(jī)制 part 8 讀寫(xiě)鎖 (ReentrantReadWriteLock) (1) 2012-09-05 14:11 我們
    但是我測(cè)試有問(wèn)題,當(dāng)同一個(gè)線(xiàn)程下一個(gè)先獲得讀鎖,就不能再進(jìn)行寫(xiě)鎖。因?yàn)樯婕暗焦卜椒ǖ那短渍{(diào)用,會(huì)出現(xiàn)這種情況,而且任何一個(gè)鎖都不能取消.對(duì)待新問(wèn)題要仔細(xì)研究,利用前人經(jīng)驗(yàn)避免一些損失.
    監(jiān)測(cè)盜用可以用隨機(jī)算法和自己特有的特性來(lái)標(biāo)示跟蹤,但是小隨機(jī)數(shù)也會(huì)產(chǎn)生測(cè)試很難遇到小可能情況從而使得隱患逃避測(cè)試  回復(fù)  更多評(píng)論
      

    # re: 深入淺出 Java Concurrency (13): 鎖機(jī)制 part 8 讀寫(xiě)鎖 (ReentrantReadWriteLock) (1) 2014-04-02 10:56 laobailong
    你那個(gè)map居然是final的,final也可以更改數(shù)據(jù)嗎?  回復(fù)  更多評(píng)論
      

    # re: 深入淺出 Java Concurrency (13): 鎖機(jī)制 part 8 讀寫(xiě)鎖 (ReentrantReadWriteLock) (1) 2014-04-02 11:28 imxylz
    @laobailong
    建議你學(xué)習(xí)下final的語(yǔ)法和用途  回復(fù)  更多評(píng)論
      


    ©2009-2014 IMXYLZ
    主站蜘蛛池模板: 亚洲午夜精品一区二区| 亚洲欧美日韩中文高清www777| 日本视频免费在线| 日本一道本不卡免费| 国产成人精品亚洲一区| 亚洲综合色7777情网站777| 亚洲免费日韩无码系列| 亚洲一区二区三区写真| 亚洲系列国产精品制服丝袜第| 亚洲人JIZZ日本人| 无码av免费一区二区三区试看| 在线观看亚洲人成网站| 青青草原亚洲视频| 日本片免费观看一区二区| 国产成人精品日本亚洲11| 亚洲AV日韩AV天堂久久| 成人免费男女视频网站慢动作| 91av视频免费在线观看| 好久久免费视频高清| 国产人成网在线播放VA免费| 久久久久亚洲精品日久生情 | 亚洲视频在线播放| 亚洲精品无码久久久久去q| 亚洲精品偷拍视频免费观看 | 亚洲综合小说另类图片动图| 亚洲男女性高爱潮网站| 亚洲一区二区影院| 亚洲毛片在线观看| 亚洲丝袜美腿视频| 91情国产l精品国产亚洲区| 亚洲av日韩av高潮潮喷无码 | 中文字幕成人免费高清在线视频| 亚洲国产美女精品久久久久| 亚洲视频在线观看网址| 亚洲精品综合久久中文字幕| 亚洲国产精品一区二区久久| 久久久国产精品亚洲一区| 亚洲A∨无码无在线观看| 亚洲一区免费观看| 亚洲狠狠ady亚洲精品大秀| 33333在线亚洲|