As you can tell I’m new to multithreading and a bit stuck here. For my program I need a thread (PchangeThread in the below example) that can be toggled on and off from another thread at any point during execution of the program.
The thread should be suspended on start and resume when pixelDetectorOn() is called.
The two threads will most likely not need to share any data except for a start/stop flag. I included a reference to the main thread anyway, just in case.
However, in the below code the only message that is ever output is “before entering loop”, which indicates that the thread never wakes up from wait() for some reason. I’m guessing this is some kind of locking problem but I haven’t been able to figure out what exactly is going wrong. Locking on this.detector from the main thread gives me the same result. Also I’m wondering if the wait()/notify() paradigm is really the way to go for suspending and waking the thread.
public class PchangeThread extends Thread {
Automation _automation;
private volatile boolean threadInterrupted;
PchangeThread(Automation automation)
{
this._automation = automation;
this.threadInterrupted = true;
}
@Override
public void run()
{
while (true) {
synchronized (this) {
System.out.println("before entering loop");
while (threadInterrupted == true) {
try {
wait();
System.out.println("after wait");
} catch (InterruptedException ex) {
System.out.println("thread2: caught interrupt!");
}
}
}
process();
}
}
private void process()
{
System.out.println("thread is running!");
}
public boolean isThreadInterrupted()
{
return threadInterrupted;
}
public synchronized void resumeThread()
{
this.threadInterrupted = false;
notify();
}
}
resumeThread() is called from the main thread the following way:
public synchronized void pixelDetectorOn(Context stateInformation) {
this.detector.resumeThread();
}
detector is a reference to an instance of PchangeThread.
The “detector”-thread is instantiated in the program’s main module the following way:
detector=new PchangeThread(this);
As you said, you need to protect access to the shared flag. You declared
threadInterruptedvolatile, but than are still using syncronized. You only need one. I prefer to just use syncronized as it makes things simpler. Multi-threading is complicated enough, keep it simple unless you know you need more complicated controls. This means that any timethreadInterruptedis read or written to, the access should be synchronized. Currently, you are not doing that insetThreadInterrupt()andisThreadInterrupted().Secondly, you want to synchronize on as small of a code block as possible. Inside of
run(), you are synchronizing over the inner loop. In actuality, you only need to to synchronize on the read ofthreadInterrupted. When the implementation ofisThreadInterrupted()is fixed as mentioned above, you can use that directly and remove the synchronized block from the inner loop.The fact that you are synchronizing on the inner loop, is the error that is causing your code to never print “thread is running!”.
PchangeThreadacquires the lock on itself and callswait()to suspend the thread. However, the thread is still holding the lock at this point. At some point later, the main thread callsresumeThread()in order to restart the thread. However, that method can not begin its execution because it must first wait to acquire the lock. However, it will never get the lock until thePchangeThreadis notified.You are providing two ways to set
threadInterrupted, but only one of them notifies the thread when the value is set to false. Do you really needsetThreadInterrupt()? I expect you don’t. If you keep it, it should act the same asresumeThread()when the argument is false.Lastly, it is better to lock on a private object instead of the instance itself. You have complete control over the private lock object. However, anyone with a reference to your thread instance could also use it as the lock for a synchronized block, which could potentially lead to a hard to find deadlock.
Your code altered to use my edits: