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()的方式。则需要全部修改