我如何使用wait / notifyAll

时间:2012-10-21 06:31:18

标签: java multithreading wait runnable notify

我想知道在java中是否有可能有一个实现Runnable的类,如果该类的对象进入wait()(所以线程停止运行直到它收到一个信号),可以是同一个类的另一个对象通知它继续运行?

理想情况下,我希望能够做到的是:

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();

 }
}

这是可能的,如果是这样,我该怎么做呢?我试图使它成为对象本身可以管理自己和所有其他相同类型的对象。因此,没有人使用这个类必须担心管理它。

4 个答案:

答案 0 :(得分:6)

  

我试图让它成为对象本身可以管理自己和所有其他相同类型的对象。因此,没有人使用这个类必须担心管理它。

如果你想让每个实例了解其他所有实例,你需要某种静态集合......这会使垃圾收集变得棘手,并且使得它很难测试。

我建议你有一个单独的经理类型,其唯一的工作是管理这个类的实例。然后你仍然只需要在一个地方拥有逻辑,但你不需要知道所有类型的实例 - 经理只需要知道它在管理什么。您甚至可以创建API,以便客户端代码需要查看管理器,并隐藏单个实例。

编辑:只是为了澄清,你可能根本不需要wait / notifyAll - 更喜欢java.util.concurrent中的更高级别的构造,它允许你编写生产者/消费者场景没有wait等低级操作。这个答案解决了让对象知道应该与哪些其他对象进行通信的更高级别的问题。一个类型的所有对象知道另一个对象的问题的想法将导致问题,因此建议经理类。

答案 1 :(得分:1)

If( condition)
{ wait }

理想情况下,等待应该被条件而不是if块所依赖。因为客户应该确保在继续之前满足条件而不是依赖于通知的soley。

答案 2 :(得分:1)

通过自我管理,您可能有意义在其锁上管理同步,并根据某些条件服从其实例变量的边界。

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();
        }

    }
}

您还应该查看Condition界面。它似乎具有完全相同的要求,除了它使用java.util.concurrent类。有一个BoundedBuffer的例子。

请参阅下面的生产者消费者示例。它具有相同的等待/通知模板。可用标志声明为volatile,因此可以对其执行线程安全读写。

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);

        }
    }

答案 3 :(得分:1)

你问了

  

同一个类的另一个对象可以通知它继续运行吗?

绝对是的! - 如果对象被阻塞等待此对象从 任何类的任何类实例调用notifyAll将允许它们运行。 (包括Runnable等待自己)

notifyAll并不关心它通知的类的类型,它会通知正在等待此对象的任何类。 (用它作锁)。

就此而言,任何类的任何实例都可以在任何对象上调用wait或notify。 wait和notify是java.lang.Object上的公共方法

请参阅本教程中的wait,notify。

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