首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >了解Synchronized的行为

了解Synchronized的行为
EN

Stack Overflow用户
提问于 2011-12-13 17:07:53
回答 3查看 115关注 0票数 2

我正在努力提高对synchronized调用期间发出的锁的作用域的理解。

例如:

代码语言:javascript
复制
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锁:

代码语言:javascript
复制
public void add(T item) {
    synchronized (items) {
        // Add item while holding the lock.
        items.add(item);
    }
}

移除它的副作用是什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-12-13 17:11:29

它只影响那些在makeSnapshot()中尝试的对象,或者更一般地说,任何其他具有synchronized( items )块的方法(这意味着它将尝试获取items对象上的锁并阻塞,直到可能为止)。

从add()方法中删除同步块的副作用是,add()不会尝试对items对象进行同步,因此将允许并发修改,包括在执行makeSnapshot()时。

在add()中没有synchronize的情况下,您可以让其他线程在制作快照时向items集合添加元素。

票数 2
EN

Stack Overflow用户

发布于 2011-12-13 17:13:44

在这段代码中,一个线程可以调用

而另一个线程调用makeSnapshot吗?

当然,这两种方法中的任何一种都可能因为ConcurrentModificationException而失败,或者列表的内容可能被破坏。

由synchronized ( items )创建的锁是影响所有对项目的尝试读取,还是仅影响通过makeSnapshot()方法尝试的读取?

都不是。锁对对象items的行为没有任何影响,只影响与其同步的块或方法-即确保没有两个线程可以同时执行这些块或方法中的任何一个。

票数 1
EN

Stack Overflow用户

发布于 2011-12-13 17:20:40

可以在一个线程调用makeSnapshot的同时调用add吗?

是。synchronized确保任何其他线程不能在同一对象(在本例中是CopyOnReadList )上输入另一个同步的代码块。由于您尚未同步add方法,因此多个线程可以并发调用add,即使一个线程正在执行makeSnapshot

通过删除add方法上的synchronized,可以使代码成为非线程安全的,因为ArrayList不是线程安全的。

经验法则是:对共享可变状态的每次访问(读或写)都必须在同一锁上同步。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8486626

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档