如何确保该方法仅在一个线程中执行一次? [英] How to make sure that method is executed only once and from one thread only?

查看:41
本文介绍了如何确保该方法仅在一个线程中执行一次?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a below method which I want to execute on below conditions:

  • 此方法只能执行一次.并且一旦执行,便无法再次执行,因此,如果有人尝试再次执行,则应通过记录一些有用的错误消息已经执行或任何有用的内容来返回.
  • 它只能由一个线程执行.因此,如果有多个线程在下面的方法中调用,那么仅应由一个线程调用该方法,而其他线程应等待初始化完成?
  • This method should be executed only once. And once it is executed, it cannot be executed again so if anyone tried to execute again, it should return back by logging some useful error message already executed or anything useful.
  • And it should be executed by only one thread only. So if multiple threads are calling below method, then it should be called by only one thread and other threads should wait for initialization to complete?

下面是我的方法:

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

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

Is this possible to do? I am working with Java 7.

推荐答案

@ShayHaned的解决方案使用锁定.您可以通过 AtomicBoolean 使其更有效,例如:

@ShayHaned's solution uses locking. You can make it more efficient via AtomicBoolean like:

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 中的工作完成.如果这样做,解决方案将变为:

The above assumes you don't have to wait for the work in startBackgroundThread to complete. If you do, the solution becomes:

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,因此它们将进入第二个分支,并且您将仅获得日志消息你想要的.

The reason this works is that AtomicBoolean.getAndSet(true) will, in one atomic operation, return the value that was previously set for and make the new value be true. So the first thread to get to your method will get false returned (since the variable was initialized to false) and it will, atomically, set it to true. Since that first thread had false returned it'll take the first branch in the if statement and your initialization will happen. Any other calls will find that wasRun.getAndSet returns true since the first thread set it to true so they'll take the 2nd branch and you'll just get the log message you wanted.

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

The CountDownLatch is initialized to 1 so all threads other than the first call await on it. They will block until the first thread calls countDown which will set the count to 0 releasing all the waiting threads.

这篇关于如何确保该方法仅在一个线程中执行一次?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆