【问题标题】:How to explicitly release CountDownLatch如何显式释放 CountDownLatch
【发布时间】:2014-11-20 08:31:35
【问题描述】:

有什么方法可以显式释放CountDownLatch - 意味着不做countDown()

例如:假设我正在等待 100 个线程来执行 countDown(),但如果出现故障,我想释放这个闩锁而不再等待。我在想@ 987654324@ 在闩锁上然后在循环中做@ 987654325@,但这不是最佳方式。

有什么建议/想法吗?

【问题讨论】:

    标签: java multithreading countdownlatch


    【解决方案1】:

    CountDownLatch 有一个重载的await() 方法,该方法将时间时间单位 作为输入,并在给定时间过去后释放锁

    【讨论】:

    • “但如果出现问题”——在这里打断不是更合适吗?
    • 我指的是 release() 方法会非常有用,就像在 Semaphore 中一样
    【解决方案2】:

    您可以使用Semaphore,它与CountDownLatch 很接近,并且它具有操作它的方法:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Semaphore.html

    【讨论】:

      【解决方案3】:

      为什么不直接使用等待超时?

      boolean await(long timeout, TimeUnit unit);
      

      如果经过指定的等待时间,则返回值 false,否则在等待完成时返回 true。

      Abort countDownLatch.await() after time out

      如果您想停止其他线程的执行,如果任何线程失败 - 您将需要一些额外的通信层。

      例如:

      AtomicBoolean kill = new AtomicBoolean(false);
      CountDownLatch latch = new CountDownLatch(SOME_NUM);
      
      class Task extends Runnable {
           public void run() {
               try {
                    ....
                    if (kill.get())
                        throw new Exception();
                    ....
               } catch (Throwable throwable) {
                  kill.set(true);
               } finally {
                  countDownLatch.countDown();
               }
           }
      }
      

      如果你只想释放 Throwable 的倒计时,不管其他进程,你可以在 Exception 的循环中做 countDown

      class Task extends Runnable {
           public void run() {
               try {
                    ....
               } catch (Throwable throwable) {
                  while(countDownLatch.getCount() != 0)
                     countDownLatch.countDown();
               } finally {
                  countDownLatch.countDown();
               }
           }
      }
      

      您可以组合 2 个倒计时任务

      CountDownLatch A = new CountDownLatch(1);
      CountDownLatch B = new CountDownLatch(1);
      
      class CountDownTracker extend Runnable {
           public void run() {
               B.await();
               A.countDown();
           }
      }
      
      class Task extends Runnable {
           public void run() {
               try {
                    ....
               } catch (Throwable throwable) {
                  A.countDown();
               } finally {
                  B.countDown();
               }
           }
      }
      

      在这种情况下,A 将在完成或任何任务失败后完成。

      等等……

      【讨论】:

      • 但万一我不知道所有操作消耗了什么,它也没用。
      • 您指定操作的最大超时时间,然后从那里开始。无论如何,您都需要某种完成超时。
      • 我不需要超时,我需要显式释放()
      • 如果你看这个问题,我想避免循环倒计时。
      • 最后一个选项,结合了 CountDownLatches。使用 while 倒计时循环没有任何成本,所以使用 while release 没有问题。
      【解决方案4】:

      除了其他答案:

      这取决于“但如果某事失败”的含义,但如果失败意味着您在工作线程中捕获了异常,您也可以在 catch 子句中倒计时。这当然会将 countDown 的含义从“已成功处理”更改为“处理完成”-因此您的代码必须处理这个..

      【讨论】:

        【解决方案5】:

        检查您的用例是否允许通过键盘交互输入解决问题。然后,您可以期望在 System.in 中手动输入,而不是 CoundDownLatch 或 Semaphore:

        Scanner sc = new Scanner(System.in);
        sc.nextLine();
        

        如果您在单元测试中需要它,请确保您的环境已设置为读取用户输入,例如在 Help -> "Edit Custom VM Options..." 中使用 -Deditable.java.test.console=true 选项启动 IntelliJ Idea

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-11-14
          • 1970-01-01
          • 1970-01-01
          • 2014-01-10
          • 2018-08-07
          • 2010-10-23
          • 2013-06-17
          相关资源
          最近更新 更多