無意發現了這個例子,拿來記住
@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;
}
}
雖然說putIfAbsent方法加了synchronized的鎖關鍵字,但是這個putIfAbsent方法獲得鎖和list對象的獲得鎖不是同一個鎖;
putIfAbsent獲得鎖是BadListHelper這個類的鎖對象,
list獲得鎖對象是list;
如果這么寫,那list依舊能夠被其他線程獲取鎖對象來改變list對象的值,就會導致數據出錯,或者兩兩線程在訪問這個方法的時候拿到的list數據可能會有錯誤;所以這么寫是不對的;
要想保證list數據不出錯,就要給他自己上鎖,其他線程將不能獲得list鎖來來改變list對象。
@ThreadSafe
class GoodListHelper <E> {
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
public boolean putIfAbsent(E x) {
synchronized (list) { //獲得list鎖對象,其他線程將不能獲得list鎖來來改變list對象。
boolean absent = !list.contains(x);
if (absent)
list.add(x);
return absent;
}
}
}