简体   繁体   中英

How do I use wait/notifyAll

I am wondering if it is possible in java to have a class that implements Runnable and if an object of the class goes to wait() (so thread stops running until it receives a signal), can another object of the same class notify it to continue running ?

Ideally what i want to be able to do is:

public class ThreadClass implements Runnable{

 public void run(){
 //.. Does some arbitrary work

  if( aCondition){  //have it wait until something signals it to contine exection.
 this.wait();
 }

 //Continues to do more work.

 //finished whatever it needed to do. Signal all other threads of this object type to continue their work.
 this.notifyAll();

 }
}

Is this possible and if so how would I go about doing it? I am trying to make it so that the object itself can manage itself and all other objects of the same type. So that no one using this class has to worry about managing it.

I am trying to make it so that the object itself can manage itself and all other objects of the same type. So that no one using this class has to worry about managing it.

If you want to make every instance know about every other instance, you'd need some sort of static collection... which then makes garbage collection tricky, as well as making it all hard to test.

I would suggest you have a separate manager type whose sole job is to manage instances of this class. Then you still only need to have the logic in one place, but you don't need to know about all instances of the type - the manager just needs to know what it's managing. You may even be able to create the API so that client code only needs to see the manager, and the individual instance are hidden.

EDIT: Just to clarify, you may not even need wait / notifyAll at all - prefer the higher-level constructs in java.util.concurrent , which allow you to write producer/consumer scenarios without low-level operations such as wait . This answer addresses the higher level question of letting objects know which other objects they should be communicating with. The question's idea of all objects of one type knowing about another will lead to problems, hence the suggestion of a manager class.

If( condition)
{ wait }

Ideally wait should be sorrounded by while condition instead of if block. Because client should make sure that the condition is satisfied before going ahead instead of soley relying on notify.

By managing itself you might be meaning to manage synchronization on its locks and obeying the boundaries for its instance variables depending on some condition.

public class ThreadClass implements Runnable {

    public void run() {
        // .. Does some arbitrary work
        synchronized (this) {
            while (! aCondition) { // have it wait until something signals it to
                                // contine exection.
                this.wait();
            }
        }

    /*  Reset the aCondition var to its old value to allow other threads to 
        enter waiting state

        Continues to do more work.

        Finished whatever it needed to do. Signal all other threads of this
         object type to continue their work.*/
        synchronized (this) {
            this.notifyAll();
        }

    }
}

You should also take a look at the Condition interface. It seems to have the exact same requirements except that it uses the java.util.concurrent classes. There is an example of the BoundedBuffer.

See the Producer Consumer Example below. It has the same wait/notify template. The available flag is declare volatile so that thread safe reads and writes can be performed on it.

public class ProducerConsumerTest {
    public static void main(String[] args) {
        CubbyHole c = new CubbyHole();
        Producer p1 = new Producer(c, 1);
        Consumer c1 = new Consumer(c, 1);

        p1.start();
        c1.start();
    }
}



    class CubbyHole {
        private int contents;
        private volatile boolean available = false;

        public int get() {
            synchronized (this) {
                while (available == false) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }

            available = false;
            synchronized (this) {
                notifyAll();
            }
            return contents;
        }

        public void put(int value) {
            synchronized (this) {
                while (available == true) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
            available = true;

            contents = value;

            synchronized (this) {
                notifyAll();
            }
        }
    }

    class Consumer extends Thread {
        private CubbyHole cubbyhole;
        private int number;
        private Integer takeSum = new Integer(0);

        public Consumer(CubbyHole c, int number) {
            cubbyhole = c;
            this.number = number;
        }

        public Integer getTakeSum() {
            return takeSum;
        }

        public void run() {
            int value = 0;
            for (int i = 0; i < 100; i++) {
                value = cubbyhole.get();
                takeSum+=value;

            }

            System.out.println("Take Sum for Consumer: " + number + " is "
                    + takeSum);
        }
    }

    class Producer extends Thread {
        private CubbyHole cubbyhole;
        private int number;
        private Integer putSum = new Integer(0);

        public Integer getPutSum() {
            return putSum;
        }

        public Producer(CubbyHole c, int number) {
            cubbyhole = c;
            this.number = number;
        }

        public void run() {
            for (int i = 0; i < 100; i++) {
                int rnd = (int) (Math.random() * 10);
                cubbyhole.put(rnd);
                putSum+=rnd;
                try {
                    sleep((int) (Math.random() * 100));
                } catch (InterruptedException e) {
                }
            }
            System.out.println("Put Sum for Producer: " + number + " is " + putSum);

        }
    }

You asked

can another object of the same class notify it to continue running ?

Absolutely yes! - if objects are blocked waiting on this object calling notifyAll from any instance of any class will allow them to run. (including the the Runnable waiting on itself)

notifyAll doesnt care about the type of a class that it notifies, it notifies ANY class that is waiting on this object. (using it as a lock).

And for that matter any instance of any class can call either wait or notify on any object. wait and notify are public methods on java.lang.Object

See this tutorial on wait, notify.

http://www.java-samples.com/showtutorial.php?tutorialid=306

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