【问题标题】:Is it possible to call a method of a locked object from another thread?是否可以从另一个线程调用锁定对象的方法?
【发布时间】:2011-10-02 11:20:46
【问题描述】:

当线程 1 拥有一个对象的内在锁时,因为

synchronized(object) {
...
}

可以打电话吗

object.method()

是否需要分别从线程 2 输入

synchronized(object) {
object.method();
}

在线程 2 中防止它在线程 1 持有锁时调用方法?

在我的例子中,我在迭代 Map 时遇到了 ConcurrentModificationExceptions,我试图通过锁定地图来防止其他线程的修改。而且我知道 ConcurrentModificationExceptions 的原因通常是在迭代期间更改了地图,但我很确定在我的情况下不是这种情况,因为迭代中只有“get”语句和一个方法调用,所以不能进行任何修改。

提前致谢。

比纳比克

【问题讨论】:

  • 愿意分享您方法的代码吗?也许里面有你没想到的东西

标签: java concurrency


【解决方案1】:

Java 中的同步是完全协作的——如果第二个线程没有选择尝试获取监视器(并且如果方法中没有任何尝试这样做),那么它不会自动锁定。

并不是对象“被锁定”——而是一个线程拥有与对象关联的锁。对象本身仍然可以被访问;如果它不需要锁,它不会阻塞。

请注意,如果您尝试迭代它并在同一循环中更改它,即使在单个线程中也可以获得 ConcurrentModificationException,例如

// Not safe: will throw an exception
for (Map.Entry<String, String> entry : map.entrySet()) {
    if (entry.getKey().equals("foo")) {
        map.put("bar", "Hello");
    }
}

这可能是您的代码中发生的情况,但我们无法确定,因为您没有向我们展示任何代码。如果您能提供一个简短但完整的程序来演示问题,我们就更有可能弄清楚发生了什么。

【讨论】:

  • 现在我又觉得自己像个白痴了,因为我写道我“非常确定没有修改”。但是有一个对侦听器的方法调用,它调用了我的类的公共方法,其中发生了修改。但在我的辩护中,这种修改是相当隐蔽的。
【解决方案2】:

当你获取锁时,它只会阻止其他线程获取相同的锁。它不会像这样锁定对象,您可以访问它的方法。

如果您遇到 ConcurrentModicationException,那么您就有了并发修改。如果您不知道这发生在哪里,则需要进一步调查。

【讨论】:

    【解决方案3】:

    除非 object.method() 是同步的,否则你可以从其他线程调用它。在非同步映射上使用迭代时必须小心。您应该使用同步映射并在迭代中同步;否则,您还必须同步所有写入操作。

    【讨论】:

    • 但是如果我用 Map map = Collections.synchronizedMap( ... ) 初始化我的地图,我的地图的方法是同步的,或者?如果我在地图上同步迭代,那么它应该是安全的吗?
    猜你喜欢
    • 2014-09-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-11
    • 2018-06-30
    • 2014-10-20
    • 2014-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多