【问题标题】:Using Synchronized in While Loops在 While 循环中使用同步
【发布时间】:2012-10-03 23:52:54
【问题描述】:

我发现以下代码不起作用,因为 while 循环无限期地窃取锁:

public void run()
{
    while(true)
    {
        synchronized(run)
        {
            if (!run) break;
            [code]
        }
    }
}

public void stopRunning()
{
    synchronized(run)
    {
        run = false;
    }
}

我的目标是确保在我知道我的 run() 函数不再实际运行之前,我不会从 stopRunning() 命令返回。我试图阻止 run 函数继续引用我正在销毁的其他东西。我的第一个想法是在 synchronized(run) 之前添加一行代码,例如 Thread.sleep(100) 以确保它释放锁。这是推荐的做法还是我忽略了什么[愚蠢/明显]?

谢谢!

【问题讨论】:

  • 我没有看到任何提示。你有什么特别的想法,你认为我可能会看到吗?
  • 也许我在这方面不正确,但是因为您在只读情况下使用运行变量,所以您不必担心使用同步。
  • 假设您将条件变量标记为 volatile,这是正确的——您不需要同步。但是 run() 可能需要一点时间才能意识到条件变量的值已经改变,并且它会继续访问正在被其他线程破坏的东西。调用 stopRunning() 的线程需要等待 run() 线程完成。

标签: android thread-safety synchronized


【解决方案1】:

如果您只需要 stopRunning() 阻止直到 run() 完成操作,您可以使用设置为 1 的 CountDownLatch。将其称为 stopSignal 或其他东西,并且在 run() 中您可以调用 stopSignal.countDown() 时它完成了。在 stopRunning 中,您可以设置 run() 完成的条件,然后调用stoppedSignal.await()。在 run() 通过倒计时“释放”闩锁之前,它不会继续。这只是一种更简洁的方法。所有被清除的同步块的东西。

提防“同步”关键字 - 这是一个非常生硬且陈旧的工具。并发包中有一些很棒的东西可以更巧妙地实现特定目的。 《Concurrency In Practice》是一本很棒的书。

【讨论】:

  • 二进制信号量也可以工作,因为我们不知道 run() 会做多少工作。条件变量需要标记为“易失性”,以便保证对它的写入对正在执行 run() 的线程可见。
  • 当使用更常见的“信号量”方法肯定有优势时,我想我一直坚持使用同步。 CountDownLatch 似乎可以解决问题。谢谢!
【解决方案2】:

这样就够了吗?

public void run()
{
    while(run)
    {
        [code]
    }

   onRunStopped();
}

public void stopRunning()
{
    run = false;
}

public void onRunStopped()
{
    // Cleanup
}

【讨论】:

    【解决方案3】:

    虽然synchronized(run) 将锁定运行,但您可以使用run.wait() 冻结执行run() 的线程。 在另一个线程中,使用run.notify()run.notifyAll() 让run() 继续。

    synchronized 用于线程之间的同步。仅当它们中的两个或更多之间存在潜在的竞争条件时才使用它。

    【讨论】:

    • 我喜欢 notify() 和 wait() 的想法,因为我认为一般的“信号量”概念最适合我的应用程序。我不知道我可以将对象视为信号量,就像同步的一样。显然有一个问题:我的 wait() 不能保证在所有情况下都在 notify() 之前被调用,这会导致致命错误。那么我只需要一个真正的信号量吗?
    【解决方案4】:

    确保“运行”对象与代码中的两个点相同。

    while 循环应该与 stopRunning() 方法同步到同一个对象。

    while 循环没有占用锁,这两条代码更有可能引用不同的对象。但我不能说,因为代码中没有显示运行对象。

    【讨论】:

      【解决方案5】:

      可能有更优雅的解决方案,但我相信您可以通过以下更改来解决它:

      private boolean lock;
      
      public void run() 
      { 
          while(true) 
          { 
              synchronized(lock) 
              { 
                  if (!run) break; 
                  [code] 
              } 
          } 
      } 
      
      public void stopRunning() 
      { 
          run = false; 
          synchronized(lock){ } 
      } 
      

      【讨论】:

        猜你喜欢
        • 2013-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-18
        • 1970-01-01
        相关资源
        最近更新 更多