同步本地变量

我有一个多线程的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

    上一篇: Synchronization on the local variables

    下一篇: What Cases Require Synchronized Method Access in Java?