对于一个集合 需要在加入之前 执行“先检查后执行”的步骤以达到“若没有则添加,若有则不添加”的目的,实行多线程以提高效率。
可惜的是这段代码并不能保证能够正确的完成工作,这是为什么呢?集合和动作都已经被synchronized修饰。问题在于在错误的锁上使用了同步,无论list使用哪一个锁来保护她的状态,可以肯定的是这个锁并不是 ListHelper的锁,ListHelper只是试用了同步的假象,尽管所有的链表操作都被生命为synchronised ,但却试用了不同的锁,这就意味着putIfAbsent相对于list的其他操作并不是原子的,因此就无法确保当putIfAbsent执行时另一个线程就不会修改链表。
要想使这个方法正确执行,必须使list在实现客户端加锁和或外部加锁时使用同一个锁,
客户端加锁是指 对于使用某个对象X的客户端代码,使用X对象本身用于保护其状态的锁来保护这段代码。
@NotThreadSafe
public class ListHelper<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;
}
}
可惜的是这段代码并不能保证能够正确的完成工作,这是为什么呢?集合和动作都已经被synchronized修饰。问题在于在错误的锁上使用了同步,无论list使用哪一个锁来保护她的状态,可以肯定的是这个锁并不是 ListHelper的锁,ListHelper只是试用了同步的假象,尽管所有的链表操作都被生命为synchronised ,但却试用了不同的锁,这就意味着putIfAbsent相对于list的其他操作并不是原子的,因此就无法确保当putIfAbsent执行时另一个线程就不会修改链表。
要想使这个方法正确执行,必须使list在实现客户端加锁和或外部加锁时使用同一个锁,
客户端加锁是指 对于使用某个对象X的客户端代码,使用X对象本身用于保护其状态的锁来保护这段代码。
@NotThreadSafe
public class ListHelper<E>{
public List<E> list =
Collections.synchronizedList(new ArrayList<E>());
public synchronized boolean putIfAbsent(E x){
synchronized(list){
boolean absent = !list.contains(x);
if(absent)
list.add(x);
return absent;
}
}
}