同步本地变量
我有一个多线程的Java代码,其中:
process()
并在那里传递它的对象; process()
以某种方式处理对象,这可能导致更改对象状态; 我已经创建了一个这样的方法:
public void process(Foo[] foos) {
for (final Foo foo : foos) {
if (foo.needsProcessing()) {
synchronized (foo) {
foo.process(); // foo's state may be changed here
}
}
}
}
据我所知,这看起来合法。 然而,IntelliJ的检查却抱怨同步本地变量,因为“不同的线程很可能有不同的本地实例”(这对我来说是无效的,因为我没有在方法中初始化foos)。
基本上我想在这里实现的是具有同步方法Foo.process()同步(这不是我的选择,因为Foo是第三方库的一部分)。
我习惯了没有黄色标记的代码,所以来自社区的任何建议都是值得赞赏的。 这对于在本地进行同步真的很糟糕吗? 有没有其他的方法可以适用于我的情况?
提前致谢!
if (foo.needsProcessing()) {
synchronized (foo) {
foo.process(); // foo's state may be changed here
}
}
我认为在上面的片段中有一个竞争条件,可能导致foo.process()
偶尔在同一个对象上被调用两次。 它应该是:
synchronized (foo) {
if (foo.needsProcessing()) {
foo.process(); // foo's state may be changed here
}
}
这与当地人同步真的很糟糕吗?
同步本地人本身并不差。 真正的问题是:
不同的线程是否在正确的对象上同步以实现适当的同步,以及
是否有其他事情可能通过同步这些对象而导致问题。
Stephen C的答案有问题,他无意义地进入了许多同步锁,奇怪的是更好的格式化方法是:
public void process(Foo[] foos) {
for (final Foo foo : foos) {
if (foo.needsProcessing()) {
synchronized (foo) {
if (foo.needsProcessing()) {
foo.process(); // foo's state may be changed here
}
}
}
}
}
获得同步锁定有时会需要一段时间,如果它保持某种状态正在改变。 这可能会改变当时foo的需求处理状态。
如果不需要处理对象,则不需要等待锁定。 当你获得锁定后,它可能不需要处理。 所以,尽管它看起来很傻,新手程序员可能倾向于删除其中一个检查,但实际上只要foo.needsProcessing()是一个可忽略的函数,它就是这样做的好方法。
回到主要问题,当你想要基于数组中的本地值进行同步时,这是因为时间非常关键。 在这些情况下,你想要做的最后一件事就是锁定数组中的每一项或者处理两次数据。 如果你有几个线程在做一堆工作,并且很少需要触摸相同的数据,但是可能会很好,你只会同步本地对象。
当且仅当处理需要处理的foo会导致并发错误时,这样做只会触发锁。 当你想基于数组中精确的对象进行同步时,你基本上会想在这种情况下使用双重门控语法。 这可以防止双处理foos并锁定任何不需要处理的foo。
你只剩下极少数情况下阻塞线程,甚至仅仅输入一个锁,并且确切地在什么时候重要,并且你的线程仅在阻塞会导致并发错误的地方被阻塞。
IDE应该可以帮助你,如果它犯了一个错误,你不应该弯下腰来取悦它。
您可以在IntelliJ中禁用此检查。 (有趣的是,它是“线程问题”中默认启用的唯一一个。这是人们犯的最普遍的错误吗?)
链接地址: http://www.djcxy.com/p/76269.html