untruste untruste - 3 months ago 11
Java Question

Wait and notify as controller-worker synchronization

I'm trying to learn to use wait and notify.

I need an application that every 10 seconds ask to the user if the thread has to continue working or not.
If not (the user presses n) the thread has to wait until the user writes 'y' on the console.

I have to use wait and notify but I don't know how to.

I'm trying to implement the wait and the notify without the prompt from the user.

This is the main class which creates two threads, FolderThread is the thread which has to work and ControlThread is the one who has to ask to the user if he wants to continue or not.

public class MainClass {

public static void main(String[] args) throws InterruptedException {
FolderThread folder = new FolderThread();
Thread t = new Thread(folder);
ControlThread control = new ControlThread(folder);
Thread t2 = new Thread(control);
t.start();
t2.start();
}
}


FolderThread

public class FolderThread implements Runnable {

@Override
public void run() {
while(true) {
System.out.println("started");
synchronized(this) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}


ControlThread

public class ControlThread implements Runnable {

FolderThread folder;

public ControlThread (FolderThread folder) {
this.folder = folder;
}

@Override
public void run() {
synchronized(folder) {
folder.notify();
}
}
}


The problem is that it prints "Started" and then it waits for a notify that will never come! Why?

Answer

What is happening here is that your notify is working, but it isn't doing anything else than just waking up the other thread, until it goes back to waiting, and then the control thread is done, so it never wakes up again the second thread.

Basically, if you want to not write the user input part, you can simulate with

Thread.sleep(2000);
// and then do what would be done if the user had type 'y'

In that case, the remaining problem is that when you notify your other thread, nothing gets done. So you need 2 things :

  1. set a "flag" somewhere, so for example pass a shared Boolean to both threads. your control thread should set that Boolean to true to tell other thread that it should stop
  2. read the "flag" from your worker thread every time he is waken up, to check whether he should stop or not

So the modifications you should do :

  1. Create an AtomicBoolean in main method :

    AtomicBoolean flag = new AtomicBoolean();
    
  2. Pass that AtomicBoolean to constructors of both threads :

    FolderThread folder = new FolderThread(flag);
    ControlThread control = new ControlThread(folder, flag);
    

    Of course you will need to adapt the constructor declarations.

  3. Get FolderThread to check on the flag when it wakes up. Replace while(true) by

    while(flag.get() == false)
    
  4. Get ControlThread to update the flag when it wants to stop it :

    flag.set( true );
    
Comments