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;
}
}