[Java 并發(fā)] 并發(fā)編程實戰(zhàn)筆記-對象的組合

編寫線程安全的代碼時,我們不希望對每次內(nèi)存訪問都進行分析一確保程序是線程安全的,而是希望將一些現(xiàn)有的安全組建組合為更大規(guī)模的組建或程序。下面介紹一些組合模式,這些模式能夠使一個類更容易成為線程安全的,并且在維護這些類是不會無意中破壞類的安全性保證的。

設(shè)計線程安全的類

在設(shè)計線程安全類的過程中,需要包含以下三個基本要素:

  • 找出構(gòu)成對象狀態(tài)的所有變量。
  • 找出約束狀態(tài)變量的不變性條件。
  • 建立對象狀態(tài)的并發(fā)訪問管理策略。

對象的狀態(tài)是由對象的域組成的,有0-n個不等,如果域都是基本類型,那這些域構(gòu)成對象的全部狀態(tài),如果有引用類型,那么該對象的狀態(tài)包括被引用對象的域(如LinkedList的狀態(tài)包括鏈表中所有節(jié)點對象的狀態(tài))。

實例封裝

如果對象不是線程安全的額,那么可以通過多種技術(shù)使他在多線程程序中安全的使用。

  1. 可以確保該對象只能由單個線程訪問(線程封閉),如JDBC Connection對對象,ThreadLocal。
  2. 通過一個鎖來保護該對象的所有訪問(Java監(jiān)視器模式),如PersonSet,代碼在后面。
  3. 封裝對象,只暴露可訪問的方法。與對象由整個程序訪問的情況比,更容易對代碼進行分析。如Collections中的UnmodifiableCollection。
// mySet不會逸出,唯一的外部引用就是PersonSet,使用Java監(jiān)視器來封裝能確保線程安全。
@ThreadSafe
    public class PersonSet {
        @GuardedBy("this")
        private final Set<Person> mySet = new HashSet<Person>();
        public synchronized void addPerson(Person p) {
            mySet.add(p);
        }
        public synchronized boolean containsPerson(Person p) {
            return mySet.contains(p);
        }
    }

將數(shù)據(jù)封裝在對象內(nèi)部,可以將數(shù)據(jù)的訪問限制在對象的方法上,從而更容易確保線程的訪問數(shù)據(jù)室總能持有正確的鎖。

線程安全性的委托

我們可以把線程安全委托給先有的線程安全類,這樣我們的代碼阿九不用關(guān)心線程安全的問題了額。這里有兩種情況:

  1. 如果委托給單獨的線程安全類,能保證線程安全。如,我們可以使用ConcurrentHashMap保存線程共享數(shù)據(jù)。
  2. 如果委托給兩個或兩個已上的線程安全類,如果存在競態(tài)條件,需要額外的同步機制保證;如果分別表示獨立的狀態(tài),可以不使用額外的同步機制即可保證線程安全。
  3. 在現(xiàn)有線程安全類中添加功能,叫作客戶端加鎖。這種機制是派生類的行為與基類耦合在一起,破壞了基類的同步策略,使用時需要特別小心。

示例代碼:

// 情況2,需要增加同步機制保證 check-than-act
public class NumberRange {
    // INVARIANT: lower <= upper
    private final AtomicInteger lower = new AtomicInteger(0);
    private final AtomicInteger upper = new AtomicInteger(0);
    public void setLower(int i) {
        // Warning -- unsafe check-then-act , need a lock
        if (i > upper.get())
            throw new IllegalArgumentException(
                    "can't set lower to " + i + " > upper");
        lower.set(i);
    }
    public void setUpper(int i) {
        // Warning -- unsafe check-then-act , need a lock
        if (i < lower.get())
            throw new IllegalArgumentException(
                    "can't set upper to " + i + " < lower");
        upper.set(i);
    }
    public boolean isInRange(int i) {
        return (i >= lower.get() && i <= upper.get());
    }
}

小結(jié)

這一章介紹了實現(xiàn)線程安全類是采用的一些技術(shù)。

  1. 線程安全可以委托給現(xiàn)有的線程安全類。
  2. 委托是創(chuàng)建線程安全的一個有效策略。
  3. 值需要讓現(xiàn)有的線程安全類管理所有的狀態(tài)即可
  4. 當(dāng)需要使用多個線程安全類保存狀態(tài)是,需要額外的同步機制保證。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,740評論 18 399
  • layout: posttitle: 《Java并發(fā)編程的藝術(shù)》筆記categories: Javaexcerpt...
    xiaogmail閱讀 6,022評論 1 19
  • 從三月份找實習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,818評論 11 349
  • 今天晚上和老二去接姐姐的路上,寶貝問:媽媽你看到QQ上老師發(fā)的視頻了?”我說:“沒看啊,今天媽媽去商場了,...
    孫若菡媽媽閱讀 271評論 0 0
  • “一個人說正經(jīng)話,說得不對可以勸他;一個人在胡言亂語,何勸之有?” 因都不愛說話,兩人倒能說到一起。 是讓小謝明白...
    Wisconsin0607閱讀 494評論 0 0

友情鏈接更多精彩內(nèi)容