我正在努力提高对synchronized调用期间发出的锁的作用域的理解。
例如:
class CopyOnReadList<T> {
private final List<T> items = new ArrayList<T>();
public void add(T item) {
items.add(item);
}
public List<T> makeSnapshot() {
List<T> copy = new ArrayList<T>();
synchronized (items) {
// Make a copy while holding the lock.
for (T t : items) copy.add(t);
}
return copy;
}
}(代码亲切地借用自this excellent answer)
在这段代码中,一个线程可以在另一个线程调用makeSnapshot的同时调用add吗?例如,synchronized (items)创建的锁是否会影响所有尝试读取items的操作,还是只影响那些通过makeSnapshot()方法尝试的读取操作?
最初的帖子实际上在add方法中使用了synchonized锁:
public void add(T item) {
synchronized (items) {
// Add item while holding the lock.
items.add(item);
}
}移除它的副作用是什么?
发布于 2011-12-13 17:11:29
它只影响那些在makeSnapshot()中尝试的对象,或者更一般地说,任何其他具有synchronized( items )块的方法(这意味着它将尝试获取items对象上的锁并阻塞,直到可能为止)。
从add()方法中删除同步块的副作用是,add()不会尝试对items对象进行同步,因此将允许并发修改,包括在执行makeSnapshot()时。
在add()中没有synchronize的情况下,您可以让其他线程在制作快照时向items集合添加元素。
发布于 2011-12-13 17:13:44
在这段代码中,一个线程可以调用
而另一个线程调用makeSnapshot吗?
当然,这两种方法中的任何一种都可能因为ConcurrentModificationException而失败,或者列表的内容可能被破坏。
由synchronized ( items )创建的锁是影响所有对项目的尝试读取,还是仅影响通过makeSnapshot()方法尝试的读取?
都不是。锁对对象items的行为没有任何影响,只影响与其同步的块或方法-即确保没有两个线程可以同时执行这些块或方法中的任何一个。
发布于 2011-12-13 17:20:40
可以在一个线程调用makeSnapshot的同时调用add吗?
是。synchronized确保任何其他线程不能在同一对象(在本例中是CopyOnReadList )上输入另一个同步的代码块。由于您尚未同步add方法,因此多个线程可以并发调用add,即使一个线程正在执行makeSnapshot。
通过删除add方法上的synchronized,可以使代码成为非线程安全的,因为ArrayList不是线程安全的。
经验法则是:对共享可变状态的每次访问(读或写)都必须在同一锁上同步。
https://stackoverflow.com/questions/8486626
复制相似问题