LinkedList 線程安全版本
class Node{
int val;
Node next;
}
class LinkedList{
Node head = null;
void pushFront(int val){}
void pushBask(int val){}
}
1.最簡單的辦法:當前鏈表對象( LinkedList this )
很多時候,線程之間有些是沒有必要互斥的
A 線程在頭插:1. 新建一個節點 2. 修改鏈表的head
B 線程在尾插:1. 新建一個節點 2. 修改鏈表最後一個節點的next
所以需要更細粒度的鎖
使用CAS方法僞代碼:
Node head=this.head;
Node node=new Node(val,head);
//CAS成功,代表頭插成功,結束
//CAS失敗,表示在這之前已經有其他線程完成頭插,我們重新獲取head再次進行頭插
while(CAS(address,head,node)==false){
head=this.head;
node.next=head;
}
使用CAS其實是放棄了強一致性:
A先開始頭插 / B後開始頭插
結果B先被調度,導致B CAS成功
B的節點就先被頭插了
2 . ConturrentHashMap
線程安全的集合類:
Vector / HashTable(不建議使用了)
順序表
不建議使用的原因是:每個方法都會帶着一個synchronized(搶一把大鎖),所以效率低
CopyOnWriteArrayList(因爲是不可變對象)
讀的時候不影響,一旦修改,會立刻賦值一份然後在自己的這份中做修改
List list =Collections.synchronized(new ArrayList() );
list是線程安全的,但是效率不高不建議使用
需要注意 ConcurrentHashMap不支持null作爲key,hashMap是支持null作爲key的。
提問:
現在已知A類是線程安全的,B類只使用了A類,問B類是線程安全的嗎?
class MyClass{
private ConcurrentHashMap=...;
public add(){
if(map.containsKey(key)){
map.deleteKey(key);
}
}
}
這個不是線程安全的:
如果A線程發現map中存在key正準備刪除,此時CPU發生調度,B線程進入,並且完成了delete操作。
現在B線程調下去,A線程再次進入就會發生刪除失敗。所以不是線程安全的。
所以線程安全是不會傳染的。
串加工廠模式:
沒有工廠的時候:
Person p=new Person();
有了工廠
Person p=PersonFactory.build();
工廠的工廠
PersonFactory pf= FactoryFactory.build();
Person p=pf.build();
作用:
加入有5000萬行代碼
new Person()寫了800萬次,分佈在各個地方。
有一天,需要修改一下new Person()的方式。則需要全部修改