位置:首页 > Java技术 > Java基础教程 > Java线程间通讯

Java线程间通讯

考虑经典的排队问题,其中一个线程正在生产一些数据,另一个是消费它。为了使问题更有趣,假设生产者必须等待,直到它会产生更多的数据消费完毕之前。

在一个轮询系统,消费者会浪费大量的CPU周期,而它等待着生产者生产。一旦生产结束了,就开始轮询,浪费更多的CPU周期等待消费者​​完成,依此类推。显然,这种情况是不希望的。

为了避免轮询,Java包括通过下面的方法优雅的进程间通信机制:

  • wait( ): 这个方法告诉调用线程放弃监视器和进入睡眠状态,直到其他线程进入同一监视器和调用notify()。

  • notify( ): 这种方法唤醒第一个线程调用wait()在同一个对象上。

  • notifyAll( ): 这种方法唤醒所有调用wait()的同一个对象上的线程。最高优先级的线程将首先运行。

这些方法被实现为final的方法在Object,因此所有的类都有它们。这三种方法都只能从一个同步的上下文中被调用。

这些方法的对象中声明。各种形式的wait( ) 存在,使可以指定一段时间等待。

例子:

下面的示例程序包括四个类:Q,想同步队列,Producer,也就是生产队列的条目线程对象;Consumer,即消耗队列的条目线程对象和PC,tiny类创建一个Q,生产者和消费者。

写这个程序在Java中正确的方法是使用wait()和notify()方法,以在两个方向的信号,如下所示:

class Q {
   int n;
   boolean valueSet = false;
   synchronized int get() {
      if(!valueSet)
      try {
         wait();
      } catch(InterruptedException e) {
         System.out.println("InterruptedException caught");
      }
      System.out.println("Got: " + n);
      valueSet = false;
      notify();
      return n;
   }

   synchronized void put(int n) {
      if(valueSet)
      try {
         wait();
      } catch(InterruptedException e) {
         System.out.println("InterruptedException caught");
      }
      this.n = n;
      valueSet = true;
      System.out.println("Put: " + n);
      notify();
   }
}

class Producer implements Runnable {
   Q q;
   Producer(Q q) {
      this.q = q;
      new Thread(this, "Producer").start();
   }

   public void run() {
      int i = 0;
      while(true) {
         q.put(i++);
      }
   }
}

class Consumer implements Runnable {
    Q q;
    Consumer(Q q) {
       this.q = q;
       new Thread(this, "Consumer").start();
    }
    public void run() {
       while(true) {
       q.get();
    }
  }
}
public class PCFixed {

   public static void main(String args[]) {
      Q q = new Q();
      new Producer(q);
      new Consumer(q);
      System.out.println("Press Control-C to stop.");
   }
}

内部的get(),wait()调用。这将导致其执行暂停,直到生产者通知有些数据已准备就绪。

当发生这种情况,执行里面的get( ) 恢复。该数据已获得后,get() 调用notify()。这告诉生产者,这都是可以的把更多的数据在队列中。

内部的put(),wait()暂停执行,直到消费者已经从队列中删除的项目。当恢复执行,数据的下一个项目被放入队列中,notify()被调用。这就告诉消费者,它现在应该将其删除。

下面是这个程序,它显示了干净的同步行为的一些输出:

Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3
Put: 4
Got: 4
Put: 5
Got: 5