天天看點

JAVA并發程式設計實戰——對象組合

4.1 設計線程安全的類

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

1.找出構成對象狀态的所有變量。

2.找出限制狀态變量的不變性條件(找出這些條件,然後對這些條件進行并發政策管理,使其線程安全)

3.建立對象狀态的并發通路管理政策。

以上三條了解為:先找出所有具有不變性條件的變量,然後确定這些變量的不變性條件是什麼,再對這些不變性條件進行并發通路政策管理(就是同步)就能設計線程安全的類。

4.1.1:收集同步需求。

確定類的線程安全,就需要確定它的不變性條件不會在并發通路的情況下破壞。

4.1.2:依賴狀态的操作

某個操作中包含有基于狀态的先驗條件,那麼這個操作就稱為依賴狀态的操作。

例如,對一個隊列進行操作,在删除元素的時候,隊列必須處于“非空”的狀态。在并發的情況下,很就有可能當你準備删除的時候,隊列不為空,但其它線程可能會導緻這種狀态發生改變。将隊列變為了空。這個也就是先驗條件。

不變性條件:比如一個Integer對象,最大值就是整數的最大值,這個就是他的不可變性。如果對其進行加法操作。并發情況下,就可能導緻不可變性發生。是的對象的狀态無效。

後驗條件:比如對一個Integer對象進行i++;那麼如果目前的值為19,那麼它的下一個值一定為20.當你擷取的時候,在并發下,那麼你可能目前值為19.下次擷取确實不是20.這就是後驗條件導緻對象狀态遷移無效。就是下一個狀态需要依賴目前狀态時。需要進行并發處理。

4.2 執行個體封閉

如果某個對象不是線程安全的,可以通過執行個體封閉的方法使其線程安全 執行個體封閉(将對象作為類的一個私有成員) 也可以封閉在某個作用域(作為一個局部變量), 線程封閉(對象在某一個線程中傳遞)

public class PersonSet {
    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);
    }
}
           

例中的PersonSet 的狀态變量是HashSet集合。 但是HashSet線程不安全。但是我們将HashSet封閉成類的一個私有成員。并将通路HashSet集合的路徑(add方法和contains方法)都進行加鎖。這樣PersonSet這個類就線程安全了。

4.2.1 Java螢幕模式:每個java對象都可以做一個實作同步的鎖,這些鎖被稱為内置鎖(Intrinsic Lock)或螢幕鎖(Monitor Lock)

java螢幕模式僅僅是一種代碼約定,對于某個類的域變量,如果能夠自始至終都使用同一種鎖對象保護的同步代碼來通路,則代碼即為遵循java螢幕模式的

public class PersonSet {
     private Integer age;

    public  synchronized Integer getAge() {
        return age;
    }

    public synchronized  void setAge(Integer age) {
        this.age = age;
    }
}