I have a thread that does several things. One of them is to just sleep for some time.
After a normal sleep it calls delayFinished() method, but if the sleep is interrupted then delayFinished() should not be called. I also need a method that aborts the sleep, that may be called by other threads.
So this is the implementation that captures my intent, but I don’t think it would work:
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();
}
}
}
If delay() is called, and while it’s sleeping, abortDelay() is called by another thread (the main use case), abortDelay() would hang on the synchronized statement since the caller of delay() owns that monitor and has not relinquished it yet.
On the other hand, if delay is implemented this way:
private void delay() {
synchronized(sleepingControl) {
sleeping=true;
}
try {
sleep(delay);
it’s possible that delay() is called, finishes the synchronized block setting
sleeping to true, but then abortDelay() is called, and it would call interrupt()
even though the thread has not yet started its sleep.
Can anyone suggest any improvements to these attempts?
You need to investigate Object.wait()/notify() instead of using sleep(). With wait() one of the crucial things is that it releases the lock on the object while waiting allowing another thread to acquire the lock and wake it up with notify().
e.g.
This is also not the whole story as wait() has a curious implementation quirk where it can spuriously wake up. So you need to manually loop the wait() call and if it returns check to see if the time has actually expired.
In reality I think you can achieve the above simpler with the
java.util.concurrentclasses. Take a look at theLockclass.