6

我想知道在 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

4 回答 4

6

我正在尝试使对象本身可以管理自己和所有其他相同类型的对象。所以使用这个类的人不必担心管理它。

如果您想让每个实例都了解其他每个实例,则需要某种静态收集……这会使垃圾收集变得棘手,并且很难测试。

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

编辑:澄清一下,您甚至可能根本不需要wait/ notifyAll- 更喜欢 中的高级构造java.util.concurrent,它允许您编写生产者/消费者场景而无需低级操作,例如wait. 这个答案解决了让对象知道他们应该与哪些其他对象通信的更高级别的问题。问题的一种类型的所有对象都知道另一种类型的想法会导致问题,因此提出了管理器类的建议。

于 2012-10-21T06:37:35.687 回答
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);

        }
    }
于 2012-10-21T07:02:18.947 回答
1

您问

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

绝对没错!- 如果对象被阻止等待此对象,则从任何类的任何实例调用 notifyAll允许它们运行。(包括 Runnable 自身等待)

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

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

请参阅本教程等待,通知。

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

于 2012-10-21T07:10:14.733 回答
1
If( condition)
{ wait }

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

于 2012-10-21T06:46:18.177 回答