【问题标题】:Synchronizing on AtomicBoolean?在 AtomicBoolean 上同步?
【发布时间】:2019-08-26 02:54:02
【问题描述】:

在我正在开发的应用程序中,我发现了以下代码 sn-p:

public class MyClass {

    private AtomicBoolean atomicBoolean = new AtomicBoolean(false);

    public void Execute() {
        // Whole lot of business logic
        // ....
        synchronized (this.atomicBoolean) {
            // Want to make sure that execution is stopped if Stop() was called
            if (this.atomicBoolean.get()) {
                throw new SpecificException("...");
            }
            // Some more business logic...
         }
     }

    public void Stop() {
        synchronized (this.atomicBoolean) {
            this.atomicBoolean.set(true);
        }
    }
}

根据 FindBugs 的说法,这是不正确的,因为我不能同时使用 AtomicBooleansynchronized 并期望它阻止对象。

我的问题是:重写此方法的正确方法是什么?我已经阅读了有关将锁定对象与布尔属性一起使用的信息,但是为该锁定引入两个新属性似乎有点笨拙。

编辑:正如下面的评论中所述:我认为目的是在两个 synchronized 块中,AtomicBoolean 不能更改,而一个线程在 synchronized 块之一中,没有其他这样的块可以输入。

【问题讨论】:

  • 是的,同步并不能阻止AtomicBoolean 在其他地方被更改,但是要就如何修复它给出一个好的建议,我们需要知道这些方法还试图做什么。
  • 为什么不让这两个方法同步呢?那将等同于您似乎想要做的事情。
  • 你为什么还要在这里使用synchronized。从表面上看,这是完全没有必要的,因为 AtomicBoolean 已经是原子的并且在没有锁定的情况下具有必要的可见性保证(并且锁定可能会导致更差的性能),所以请解释你的原因和你想要实现的目标,以便我们解释你的想法是错误的(或正确的)。在所示代码中,您最好使用普通的boolean 变量而不是AtomicBoolean
  • 虽然将原子变量与 synchronized 一起使用看起来很可疑,但我想知道 FindBugs 是专门针对这种组合,还是只是抱怨 atomicBoolean 没有被声明为 final。后者很容易解决。
  • 嗯,是的,关于混乱是正确的。在这里,就您的示例所示而言,您可以使用不带AtomicBooleansynchronized 或不带synchronizedAtomicBoolean,它仍然可以工作。事实上,private volatile boolean stop; 也可以。

标签: java multithreading java-8 synchronized atomicboolean


【解决方案1】:

...我不能同时使用 AtomicBoolean 和同步...

无论价值如何,该语言都允许您在任何对象上进行同步。

就风格而言,一些程序员更喜欢只在不用于其他目的的私有对象上进行同步。

private static Object foobarLock = new Object();
...
public void fooItUp(...) {
    ...
    synchronized(foobarLock) {
        ...
    }
    ...
}

...并期望它阻止对象

需要明确的是,当某个线程 T 进入 synchronized (o) {...} 块时,不会阻止其他线程访问或修改对象 o。它唯一阻止的是,它阻止了一些其他线程 U 同时进入同一对象 o 上的同步块。

【讨论】:

    【解决方案2】:

    只需替换这两种方法中的synchronized (this.atomicBoolean) { 部分,AtomicBoolean::getAtomicBoolean::set 已经是原子的。

    【讨论】:

    • 我希望 AtomicBoolean 在同步块内被进一步操作,假设它们不会被其他线程修改(错误的)。如果是这种情况,那么简单地删除同步块不会使代码正确。
    • 感谢您的快速回复!我对我的问题进行了一些编辑以提供更多信息。我对您提出的解决方案有一个疑问:我认为不能在Execute()synchronized 块内修改AtomicBoolean 的值(我编辑之前的Method1())。如果我正确理解了您的答案,您的解决方案就不会是这种情况,对吗?
    • @Jdv 似乎这充当了exit 标志,一旦设置,您必须抛出异常并完成。对吗?
    • @Eugene 我认为它应该更像是一个计划外的cancel。如果在Execute() 期间调用Stop(),则后者不应完成,而是抛出Excepton。如果不是这样,在Execute() 中的synchronized 块期间,应该不可能执行Stop()
    • @Jdv 这是一个加载的问题,因为它暗示需要同步部分的假设。
    猜你喜欢
    • 2016-06-21
    • 2013-06-13
    • 2014-09-22
    • 2013-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    • 2014-10-04
    相关资源
    最近更新 更多