1_基礎(chǔ)知識(shí)_chapter04_對(duì)象的組合_4_在現(xiàn)有的線程安全類中添加功能

  • 很多情況下應(yīng)該重用現(xiàn)有的類, 添加自定義的功能, 此時(shí)需要在不破壞線程安全性的情況下添加新的操作

    (1) 方法一: 直接修改原始的類

    優(yōu)點(diǎn): 同步策略仍然處于同一個(gè)源代碼文件中, 更容易理解和維護(hù)

    缺點(diǎn): 常常無(wú)法修改源代碼

    (2) 方法二: 擴(kuò)展這個(gè)類

    同步策略分布到了各個(gè)文件中, 并且要確定的得知基類的同步策略

示例

    @ThreadSafe
    public class BetterVector<E> extends Vector<E> {

        // When extending a serializable class, you should redefine serialVersionUID
        static final long serialVersionUID = -3963416950630760754L;

        public synchronized boolean putIfAbsent(E x) {

            boolean absent = !super.contains(x);
            if (absent) {
                super.add(x);
            }

            return absent;
        }
    }

(3) __方法三: 客戶端加鎖機(jī)制__

擴(kuò)展類的功能, 但不是擴(kuò)展類本身, 而是將擴(kuò)展代碼放入__輔助類__中

__客戶端加鎖__: 對(duì)于使用某個(gè)對(duì)象X的客戶端代碼, 使用__X本身用于保護(hù)其狀態(tài)的鎖__來(lái)保護(hù)這段客戶代碼

__所以, 使用客戶端加鎖方式, 必須從源碼中找到X使用的是哪一個(gè)鎖__


示例

錯(cuò)誤示例

    @NotThreadSafe
    class BadListHelper<E> {

        public List<E> list = Collections.synchronizedList(new ArrayList<E>());

        public synchronized boolean putIfAbsent(E x) {

            boolean absent = !list.contains(x);

            if (absent) {
                list.add(x);
            }

            return absent;
        }
    }

正確示例

    @ThreadSafe
    class GoodListHelper<E> {

        public List<E> list = Collections.synchronizedList(new ArrayList<E>());

        public boolean putIfAbsent(E x) {

            synchronized (list) {
        
                boolean absent = !list.contains(x);

                if (absent) {
                    list.add(x);
                }

                return absent;
            }
        }
    }

正確示例和錯(cuò)誤示例的區(qū)別在于使用鎖的不同, 深入Collections.synchronizedList的源碼, 會(huì)發(fā)現(xiàn)它使用的鎖就是Collections.synchronizedList對(duì)象本身, 所以輔助類中也要使用Collections.synchronizedList本身作為鎖


和方法二一樣, 客戶端加鎖方式也存在同步策略分布在各個(gè)類中的問(wèn)題, 這樣當(dāng)?shù)讓釉创a的同步策略改變時(shí)可能會(huì)不穩(wěn)烛芬。

(4) __方法四: 組合__

__使用Java監(jiān)視器模式, 對(duì)內(nèi)部的對(duì)象完全由類本身提供的鎖保護(hù), 不管底層的類是否線程安全__

示例

    @ThreadSafe
    public class ImprovedList<T> implements List<T> {

        private final List<T> list;

        public ImprovedList(List<T> list) {
            this.list = list;
        }

        public synchronized boolean putIfAbsent(T x) {

            boolean contains = list.contains(x);
            if (contains) {
                list.add(x);
            }

            return !contains;
        }

        // Plain vanilla delegation for List methods.
        // Mutative methods must be synchronized to ensure atomicity of putIfAbsent.

        public synchronized boolean addAll(Collection<? extends T> c) {
            return list.addAll(c);
        }

        public synchronized boolean addAll(int index, Collection<? extends T> c) {
            return list.addAll(index, c);
        }

        public synchronized boolean removeAll(Collection<?> c) {
            return list.removeAll(c);
        }

        public synchronized boolean retainAll(Collection<?> c) {
            return list.retainAll(c);
        }

        public synchronized void clear() {
            list.clear();
        }

        public synchronized boolean add(T e) {
            return list.add(e);
        }

        public synchronized boolean remove(Object o) {
            return list.remove(o);
        }


        public int size() {
            return list.size();
        }

        public boolean isEmpty() {
            return list.isEmpty();
        }

        public boolean contains(Object o) {
            return list.contains(o);
        }

        public Iterator<T> iterator() {
            return list.iterator();
        }

        public Object[] toArray() {
            return list.toArray();
        }

        public <T> T[] toArray(T[] a) {
            return list.toArray(a);
        }

        public boolean containsAll(Collection<?> c) {
            return list.containsAll(c);
        }

        public boolean equals(Object o) {
            return list.equals(o);
        }

        public int hashCode() {
            return list.hashCode();
        }

        public T get(int index) {
            return list.get(index);
        }

        public T set(int index, T element) {
            return list.set(index, element);
        }

        public void add(int index, T element) {
            list.add(index, element);
        }

        public T remove(int index) {
            return list.remove(index);
        }

        public int indexOf(Object o) {
            return list.indexOf(o);
        }

        public int lastIndexOf(Object o) {
            return list.lastIndexOf(o);
        }

        public ListIterator<T> listIterator() {
            return list.listIterator();
        }

        public ListIterator<T> listIterator(int index) {
            return list.listIterator(index);
        }

        public List<T> subList(int fromIndex, int toIndex) {
            return list.subList(fromIndex, toIndex);
        }
    }

所有需要同步的方法都使用ImprovedList本身的鎖, 而不必在意封裝對(duì)象的同步策略
  • 同步策略應(yīng)該文檔化

    定義好

    (1) 哪些變量為volatile

    (2) 哪些變量用鎖保護(hù)

    (3) 哪些變量必須不可變或者線程封閉

    (4) 哪些操作必須是原子操作

    等……

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末峰伙,一起剝皮案震驚了整個(gè)濱河市遵倦,隨后出現(xiàn)的幾起案子鞍匾,更是在濱河造成了極大的恐慌,老刑警劉巖愧哟,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奥吩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蕊梧,警方通過(guò)查閱死者的電腦和手機(jī)霞赫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)肥矢,“玉大人端衰,你說(shuō)我怎么就攤上這事「矢模” “怎么了旅东?”我有些...
    開(kāi)封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)十艾。 經(jīng)常有香客問(wèn)我抵代,道長(zhǎng),這世上最難降的妖魔是什么忘嫉? 我笑而不...
    開(kāi)封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任荤牍,我火速辦了婚禮案腺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘参淫。我一直安慰自己救湖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布涎才。 她就那樣靜靜地躺著,像睡著了一般力九。 火紅的嫁衣襯著肌膚如雪耍铜。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天跌前,我揣著相機(jī)與錄音棕兼,去河邊找鬼。 笑死抵乓,一個(gè)胖子當(dāng)著我的面吹牛伴挚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播灾炭,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼茎芋,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蜈出?” 一聲冷哼從身側(cè)響起田弥,我...
    開(kāi)封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎铡原,沒(méi)想到半個(gè)月后偷厦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡燕刻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年只泼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卵洗。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡请唱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出忌怎,到底是詐尸還是另有隱情籍滴,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布榴啸,位于F島的核電站孽惰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鸥印。R本人自食惡果不足惜勋功,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一坦报、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狂鞋,春花似錦片择、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至信不,卻和暖如春嘲叔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背抽活。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工硫戈, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人下硕。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓丁逝,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親梭姓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子霜幼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容

  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司糊昙,掛了不少辛掠,但最終還是拿到小米、百度释牺、阿里萝衩、京東、新浪没咙、CVTE猩谊、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,218評(píng)論 11 349
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,093評(píng)論 1 32
  • Java8張圖 11、字符串不變性 12祭刚、equals()方法牌捷、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,697評(píng)論 0 11
  • 今天是冬至涡驮,二十四節(jié)氣中的一天暗甥。 這一天并沒(méi)有什么不同,依舊是星期二捉捅,依舊早上九點(diǎn)起床撤防,半小時(shí)后出門,買好早餐去上...
    冷汐閱讀 304評(píng)論 0 0
  • 這是一個(gè)發(fā)生在我支教生涯里的真實(shí)故事棒口。 事情是這樣的寄月,某個(gè)下午的英語(yǔ)課上辜膝,我在講臺(tái)上講課,講臺(tái)下第二排的一位男生往...
    Steven文旭閱讀 608評(píng)論 0 3