【问题标题】:How do I use wait/notifyAll如何使用 wait/notifyAll
【发布时间】:2012-10-11 07:50:05
【问题描述】:

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

 }
}

这可能吗?如果可以,我将如何去做?我正在尝试使对象本身可以管理自己和所有其他相同类型的对象。这样使用这个类的人就不用担心管理它了。

【问题讨论】:

    标签: java multithreading wait runnable notify


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 对如何制作经理有帮助吗?目前我只有一个类创建我的线程对象,但不是每个线程都会暂停 - 我预计大约 1/10 线程需要停止,直到另一个线程释放资源。
    • @user597608:我们需要了解更多信息——我们真的不知道它试图做什么。如果您可以让您的经理负责创建每个实例,那么它可以将自己的引用传递给每个实例,这样他们就可以在需要向同一经理管理的其他实例发出信号时回调......确实对你有帮助吗?
    • 我正在创建一个等待 UDP 调用的服务器。它会收到一条消息,然后创建一个新线程来解析该消息,然后将其输入 SQLite 数据库。由于 sqlite 数据库是一个文件,我遇到了数据库锁定的问题。我尝试了一个连接池(BoneCP),但它只是将我的代码性能降低了 1/10。目前我的服务器可以处理 10 条消息/秒,但任何高于此的速度都会崩溃。
    • @user597608:我对 SQLite 的了解还不够,无法肯定地说,但听起来你最好只使用 一个 线程来访问 SQLite。我也建议不要为每条消息创建一个新线程 - 只需保留一个池即可。您可能需要两个生产者/消费者队列:一个网络侦听器将原始数据包放在一个队列上,该队列可能被多个解析线程使用。然后每个解析线程使用相同的 SQLite 队列,该队列仅由一个执行串行 DB 工作的线程提供服务。
    • 我想过这个问题,但我可能会遇到内存不足的问题。理想情况下,我想要的是一个实际的数据库,所以我什至不必担心这个:(
    【解决方案2】:
    If( condition)
    { wait }
    

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

    【讨论】:

      【解决方案3】:

      你问

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

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

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

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

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

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

      【讨论】:

      • OP 没有“错误地提出问题”——他发布的代码并没有按照他的意愿去做,但这不是一回事。
      【解决方案4】:

      通过管理自身,您可能意味着管理其锁的同步并根据某些条件遵守其实例变量的边界。

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

      【讨论】:

      • 试过了,我遇到的唯一问题是没有通知调用,线程没有被唤醒。
      • CubbyHole Producer-Consumer 示例是理解等待/通知机制的好方法。我已经在与上面相同的模板中完成了。
      猜你喜欢
      • 2012-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-20
      • 2011-09-11
      • 1970-01-01
      • 1970-01-01
      • 2013-02-23
      相关资源
      最近更新 更多