我有一个做一些事情的线程。其中一个就是睡一段时间。
正常睡眠后,它会调用delayFinished()
方法,但如果睡眠中断,则不应调用delayFinished()
。我还需要一个中止睡眠的方法,可以被其他线程调用。
所以这是捕获我意图的实现,但我认为它不会起作用:
public class MyThread extends Thread {
private boolean sleeping=false;
private Object sleepingControl=new Object();
//... other unrelated stuff...
private void delay() {
try {
synchronized(sleepingControl) {
sleeping=true;
sleep(delay);
sleeping=false;
delayFinished();
}
} catch (InterruptedException e) {
sleeping=false;
}
}
public void abortDelay() {
synchronized(sleepingControl) {
if (sleeping)
interrupt();
}
}
}
如果调用了delay()
,并且在它休眠时,abortDelay()
被另一个线程调用(主用例),abortDelay()
将挂起在同步语句上,因为调用者{ {1}}拥有该监视器并且还没有放弃它。
另一方面,如果以这种方式实现延迟:
delay()
可能会调用 private void delay() {
synchronized(sleepingControl) {
sleeping=true;
}
try {
sleep(delay);
,完成同步块设置
睡到真,但然后调用delay()
,它会调用abortDelay()
即使线程尚未开始睡眠。
有人可以建议对这些尝试进行任何改进吗?
答案 0 :(得分:6)
您需要调查Object.wait()/ notify()而不是使用sleep()。使用wait()时,其中一个关键的事情就是它在释放对象的锁定时等待允许另一个线程获取锁并使用notify()将其唤醒。
e.g。
public class MyThread extends Thread {
private boolean aborted = false;
private final Object sleepingControl=new Object();
//... other unrelated stuff...
private void delay() {
try {
synchronized(sleepingControl) {
sleepingControl.wait(delay);
if (!aborted)
delayFinished();
}
} catch (InterruptedException e) {
}
}
public void abortDelay() {
synchronized(sleepingControl) {
aborted = true;
sleepingControl.notify();
}
}
}
这也不是全部故事,因为wait()有一个奇怪的实现怪癖,它可以虚假地唤醒。因此,您需要手动循环wait()调用,如果它返回检查以查看时间是否实际到期。
实际上,我认为你可以使用java.util.concurrent
类实现上述更简单。看一下Lock
课程。
答案 1 :(得分:0)
sleeping
设置为volatile并从abortDelay
中删除同步。然后,您唯一的问题是abortDelay
可能会在delay
行之前立即抓住sleeping = false;
。因此,在两行之后,请致电interrupted()
以清除可能的设置。
更正/详细说明: abortDelay
需要同步。代码应如下所示:
private final Object sleepingControl = new Object();
private volatile boolean sleeping;
private void delay() {
try {
sleeping=true; // Synching not needed.
sleep(delay);
// Thread COULD be interrupted at this point!
// Now makes sure abortDelay sees this change.
synchronized (sleepingControl) {
sleeping = false;
// Thread can no longer be interrupted.
// Clear flag if it is set.
interrupted();
}
delayFinished();
}
catch (InterruptedException e) {
// Thread COULD be interrupted at this point!
synchronized (sleepingControl) {
sleeping = false;
// Thread can no longer be interrupted.
// Clear flag if it is set.
interrupted();
}
}
}
public void abortDelay() {
synchronized (sleepingControl) {
if (sleeping)
// At this point, "sleeping" HAS to be true.
interrupt();
}
}