【问题标题】:How to synchronize code based on boolean value?如何根据布尔值同步代码?
【发布时间】:2021-02-16 23:08:39
【问题描述】:

我有这个代码:

    private volatile boolean immortal;
    private Object lock = new Object();
    
    public void set(boolean immortal) {
        this.immortal = immortal;
    }

    public void kill() {
       // .... contains some other code. 
       synchronized(lock) {
            if (!immortal) {
               for (int i = 0; i < numThreads; i++) {
                   runnableList.add(POISON_PILL);
               }
            }
       }
    }

我的用例是我希望 kill 方法中的 if 语句在 immortal 值更改之前运行完成。有没有更好的方法在不锁定对象的情况下做到这一点?

我的意思是,仅当布尔变量的值为 false 并且在运行完成之前不允许更改布尔值时,同步块的最佳方法是什么?我可以使用AtomicBoolean 来实现吗?

【问题讨论】:

  • “在运行完成之前不允许更改布尔值”-您当前的实现是否应该实现这一点?据我所知,没有什么能阻止其他线程在执行同步块期间更改immortal

标签: java concurrency synchronization atomic synchronized


【解决方案1】:

一种巧妙的方法是将您的runnableList 声明为同步列表:

// where T is whatever type it needs to be
List<T> runnableList = Collections.synchronizedList(new ArrayList<>());

然后你可以在没有显式同步的情况下添加它:

if (!immortal) {
  runnableList.addAll(Collections.nCopies(numThreads, POISON_PILL));
}

这是有效的,因为对 addAll 的单个调用是原子的。

这不是在没有同步的情况下这样做的,它只是在列表内部。


话虽如此,很难推荐“更好”的解决方案,因为不清楚要求是什么。同步(等)用于在多线程操作时保留对象的不变量。

例如,为什么在向runnableList 添加内容时需要immortal 保持不变?您还如何访问immortalrunnableList?等等

【讨论】:

    【解决方案2】:

    使用两把锁:

    private boolean immortal;
    private final Object killMonitor = new Object();
    private final Object flagMonitor = new Object();
    
    public void set(boolean immortal) {
        synchronized (flagMonitor) {
            this.immortal = immortal;
        }
    }
    
    public void kill() {
        // ...
        synchronized (flagMonitor) {
            if (!immortal) {
                synchronized (killMonitor) {
                    runnableList.addAll(Collections.nCopies(numThreads, POISON_PILL));
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-03-12
      • 1970-01-01
      • 2019-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多