java - 如何确保该方法仅从一个线程执行一次?

标签 java multithreading concurrency

我有一个下面的方法,我想在下面的条件下执行:

  • 这个方法应该只执行一次。一旦执行,就无法再次执行,因此如果有人试图再次执行,它应该通过记录一些有用的错误消息 already executed 或任何有用的信息返回。
  • 而且它应该只由一个线程执行。那么如果多个线程都在调用下面的方法,那么它应该只被一个线程调用,其他线程应该等待初始化完成?

下面是我的方法:

  public void initialize() {
    List<Metadata> metadata = getMetadata(true);
    List<Process> process = getProcess();
    if (!metadata.isEmpty() && !process.isEmpty()) {
        Manager.setAllMetadata(metadata, process);
    }
    startBackgroundThread();
  }

这可能吗?我正在使用 Java 7。

最佳答案

@ShayHaned 的解决方案使用锁定。您可以通过 AtomicBoolean 提高效率,例如:

AtomicBoolean wasRun = new AtomicBoolean(false);
CountDownLatch initCompleteLatch = new CountDownLatch(1);

public void initialize() {
  if (!wasRun.getAndSet(true)) {
      List<Metadata> metadata = getMetadata(true);
      List<Process> process = getProcess();
      if (!metadata.isEmpty() && !process.isEmpty()) {
          Manager.setAllMetadata(metadata, process);
      }
      startBackgroundThread();
      initCompleteLatch.countDown();
  } else {
      log.info("Waiting to ensure initialize is done.");
      initCompleteLatch.await();
      log.warn("I was already run");
  }
}

以上假定您不必等待 startBackgroundThread 中的工作完成。如果这样做,解决方案将变为:

AtomicBoolean wasRun = new AtomicBoolean(false);
CountDownLatch initCompleteLatch = new CountDownLatch(1);

public void initialize() {
  if (!wasRun.getAndSet(true)) {
      List<Metadata> metadata = getMetadata(true);
      List<Process> process = getProcess();
      if (!metadata.isEmpty() && !process.isEmpty()) {
          Manager.setAllMetadata(metadata, process);
      }
      // Pass the latch to startBackgroundThread so it can
      // call countDown on it when it's done.
      startBackgroundThread(initCompleteLatch);
  } else {
      log.info("Waiting to ensure initialize is done.");
      initCompleteLatch.await();
      log.warn("I was already run");
  }
}

这样做的原因是 AtomicBoolean.getAndSet(true) 将在一个原子操作中返回先前设置的值并使新值成为 true。因此,到达您的方法的第一个线程将返回 false(因为变量已初始化为 false),并且它会以原子方式将其设置为 true。由于第一个线程返回了 false,它将采用 if 语句中的第一个分支,然后您的初始化就会发生。任何其他调用都会发现 wasRun.getAndSet 返回 true,因为第一个线程将其设置为 true,因此它们将采用第二个分支,您只会收到日志消息你想要的。

CountDownLatch 初始化为 1,因此除第一个线程之外的所有线程都对其调用 await。它们将阻塞,直到第一个线程调用 countDown,这会将计数设置为 0,释放所有等待的线程。

关于java - 如何确保该方法仅从一个线程执行一次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42047944/

相关文章:

java - 是否有任何好的 API 可以维持 Flash <--> Java 之间的开放连接

java - 实现同步以获得正确的线程输出

Python - 多线程/多处理

java - Java内存模型中局部最终变量的语义?

java - int 和 Integer 影响并发结果

java - TableColumnModelListener。 JPanel revalidate() 方法破坏了 swing 元素的组合

java - 如何设置特定用户运行processBuilder?

java - 如何让 TestNG 在关闭之前等待我的测试完成

ios - NSPersistentContainer 的核心数据并发

python - 识别 Pandas 数据框中并发事件的简单方法