Thread.sleep()与Thread.onSpinWait的区别

5

我有一个自旋等待循环,它正在忙等待标志被设置。然而,这可能需要很长时间 - 几分钟甚至几小时。

使用Thread.sleep()Thread.onSpinWait()更有效吗?

3个回答

7

根据Thread#onSpinWait的文档:

运行时可能会采取措施以提高调用自旋等待循环结构的性能。

Thread#sleep不会这样做,而是释放处理器给其他可运行线程,直到其睡眠时间已过。

如果我是你,我会重新设计你的系统以使用中断(事件)而不是轮询(忙等待),因为这将比Thread#sleepThread#onSpinWait都有更好的性能提升。


2

在这种情况下,你既不需要睡眠也不需要自旋锁。 睡眠是错误的选择,因为你不知道需要多长时间才能醒来。 使用自旋锁循环也是错误的,因为自旋锁是忙等待,会消耗CPU周期,并且只适用于非常短的等待,以期望资源变得非常快速可用。 在这里,你需要设置一个信号量。 让线程1等待线程2设置信号量。


2
所以您想看一个关于Object及其长期可用的wait()notify/All()方法的简短示例吗?(它们已经在20多年前的JLS 1.0存在了)。
不用说了:
public class NotifyTest {
  private boolean flag = false;
  public synchronized boolean getFlag() {
    return flag;
  }
  public synchronized void setFlag(boolean newFlag) {
    flag = newFlag;
    notifyAll();
  }

  public static void main(String[] args) throws Exception {
    final NotifyTest test = new NotifyTest();

    new Thread(new Runnable() {
      @Override
      public void run() {
        System.out.printf("I am thread at %,d, flag is %b\n",
                          System.currentTimeMillis(), test.getFlag());
        synchronized (test) {
          try {
            test.wait();
          } catch (InterruptedException ie) {
            ie.printStackTrace();
          }
        }
        System.out.printf("I am thread at %,d, flag is %b\n",
                          System.currentTimeMillis(), test.getFlag());
      }
    }).start();

    System.out.printf("I am main at %,d, flag is %b\n",
                      System.currentTimeMillis(), test.getFlag());
    Thread.sleep(2000);
    test.setFlag(true);
    System.out.printf("I am main at %,d, flag is %b\n",
                      System.currentTimeMillis(), test.getFlag());
  }
}

如果您的等待循环还有其他事情要做,Object.wait()也有带有超时的变体。
因此,对象可以被wait(),然后等待线程可以被通知(通过notify()中的其中一个等待者或通过notifyAll()中的所有等待者),它们甚至不必彼此了解。
由于等待和通知都必须在同步块内发生,因此启动块、检查变量/标志/任何内容并有条件地发出等待是安全而可行的(这些构造在此处未显示)。

有趣。我不知道这些方法的存在 - 谢谢! - Tirafesi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接