简体   繁体   中英

A simple wait() & notify() example - doesn't work

I tries to write a simple example that demonstrates a remote controller opertation. The input is being accepted via the console, and a message is being printed accordingly.

Both threads run infinite loops: the main thread waits for notification, while the other waits for a console input.

I'd like to know how to fix it. The problem is that the notify doesn't stop the waiting: in other words, the words "before wait" are printed, but the words "after wait" are not. BTW, without the while(true) loops it works fine (for one button press).

Many thanks

    public class MainTV {
    public static int lastRemoteCode = 0;   
    public static void main(String[] args){
        RemoteControllerThread remote = new RemoteControllerThread();
        remote.start();
        synchronized(remote){
            while(true){                    
                try {
                    System.out.println("before wait");
                    remote.wait();
                    System.out.println("after wait");
                    switch (lastRemoteCode){ //we use switch because there are many code options
                    case 0:
                        System.out.println("Error with remote button reading");
                        break;
                    case 3:
                        System.out.println("Volume Down button was pressed now!");
                        break;
                    case 4:
                        System.out.println("Volume Up button was pressed now!");
                        break;
                    }
                } catch (InterruptedException e) {                  
                    e.printStackTrace();
                }               

            }
        }
    }
}

and the second class (simulates the remote controller):

    import java.util.Scanner;
    public class RemoteControllerThread extends Thread{
    public void run(){
        synchronized(this){
            Scanner in = new Scanner(System.in); 
            while(true){
                System.out.println("Press a button in the remote please...");
                int code = in.nextInt();                
                MainTV.lastRemoteCode = code;
                System.out.println("before notify");
                notify();   
                System.out.println("after notify");
            }
        }
    }
}

I think there are two problems with your code.

  1. When the main thread execution reaches synchronized(remote) it might not continue because the remote controller thread (possibly) already locked the remote object. Move remote.start() into synchronized(remote) block.

  2. In order to let execution continue from wait you need to release the object lock after notify . Change syncronization block in thread like:

-

public void run() {
    Scanner in = new Scanner(System.in); 
    while(true){
        System.out.println("Press a button in the remote please...");
        int code = in.nextInt();                
        MainTV.lastRemoteCode = code;
        System.out.println("before notify");

        synchronized(this) {
            notify();   
        }

        System.out.println("after notify");
    }
}

Both threads synchronize on the same object, this refers to the same object as remote and since both this synchronize blocks have infinite loops inside, this creates a problem. One of the thread will wait for the other one to finish, which never happens (because of the infinite loops).

To fix this, you should synchronize only the code that needs to be synchronized, like the wait() and notify() calls.

To quote from notify() JavaDoc:

The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object

Your remote never lets go of the lock. If you switch the synchronized with the while , you have a slim chance, but usually you remote will get the lock back immediately. The following works, for instance:

class RemoteControllerThread extends Thread {
    public void run() {
        while (true) {
            synchronized (this) {
                Scanner in = new Scanner(System.in);
                System.out.println("Press a button in the remote please...");
                int code = in.nextInt();
                MainTV.lastRemoteCode = code;
                System.out.println("before notify");
                notify();
                System.out.println("after notify");
            }
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM