我有一个旋转等待循环,正忙于等待设置标志。但是,这可能需要很长时间(strong)-几分钟甚至几小时。
答案 0 :(得分:6)
来自Thread#onSpinWait
的{{3}}:
运行时可能会采取措施来改善调用自旋等待循环构造的性能。
Thread#sleep
不会执行此操作,而是将处理器释放到另一个可运行线程,直到其睡眠时间结束。
如果我是您,我将重新设计您的系统,使其使用中断(事件)而不是轮询(繁忙等待),因为这将比Thread#sleep
或Thread#onSpinWait
带来更好的性能提升。
答案 1 :(得分:1)
在这种情况下,睡眠和自旋锁都不是您想要的。睡眠是错误的选择,因为您不知道需要多长时间才能入睡。进行某种自旋锁循环是错误的,因为自旋锁忙于等待,从而消耗了CPU周期,并且实际上仅意味着非常短的等待,以预期资源会很快变得可用。您要在此处设置信号灯。让线程1等待信号2设置信号量。
答案 2 :(得分:1)
因此,您想看看有关Object
及其长期可用的wait()
和notify/All()
方法的简短示例吗? (它们已经在20年前的there中的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()
的所有侍者),甚至不必须彼此了解。
由于等待和通知都必须在同步块内进行,因此安全且有可能启动该块,检查变量/标志/任何内容并有条件地发出等待(只是此处未显示这些构造)。