Java提供了3个非常重要的方法来巧妙地解决线程间的通信问题。这3个方法分别是:wait()、notify()和notifyAll()。它们都是Object类的最终方法,因此每一个类都默认拥有它们。
虽然所有的类都默认拥有这3个方法,但是只有在synchronized关键字作用的范围内,并且是同一个同步问题中搭配使用这3个方法时才有实际的意义。
这些方法在Object类中声明的语法格式如下所示:
final void wait() throws InterruptedException
final void notify()
final void notifyAll()
其中,调用wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行态退出,进入等待队列,直到被再次唤醒。而调用notify()方法可以唤醒等待队列中第一个等待同一共享资源的线程,并使该线程退出等待队列,进入可运行态。调用notifyAll()方法可以使所有正在等待队列中等待同一共享资源的线程从等待状态退出,进入可运行状态,此时,优先级最高的那个线程最先执行。显然,利用这些方法就不必再循环检测共享资源的状态,而是在需要的时候直接唤醒等待队列中的线程就可以了。这样不但节省了宝贵的CPU资源,也提高了程序的效率。
由于wait()方法在声明的时候被声明为抛出InterruptedException异常,因此,在调用wait()方法时,需要将它放入try…catch代码块中。此外,使用该方法时还需要把它放到一个同步代码段中,否则会出现如下异常:
"java.lang.IllegalMonitorStateException: current thread not owner"
这些方法是不是就可以实现线程间的通信了呢?下面将通过多线程同步的模型: 生产者和消费者问题来说明怎样通过程序解决多线程间的通信问题。
具体步骤
虽然所有的类都默认拥有这3个方法,但是只有在synchronized关键字作用的范围内,并且是同一个同步问题中搭配使用这3个方法时才有实际的意义。
这些方法在Object类中声明的语法格式如下所示:
final void wait() throws InterruptedException
final void notify()
final void notifyAll()
其中,调用wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行态退出,进入等待队列,直到被再次唤醒。而调用notify()方法可以唤醒等待队列中第一个等待同一共享资源的线程,并使该线程退出等待队列,进入可运行态。调用notifyAll()方法可以使所有正在等待队列中等待同一共享资源的线程从等待状态退出,进入可运行状态,此时,优先级最高的那个线程最先执行。显然,利用这些方法就不必再循环检测共享资源的状态,而是在需要的时候直接唤醒等待队列中的线程就可以了。这样不但节省了宝贵的CPU资源,也提高了程序的效率。
由于wait()方法在声明的时候被声明为抛出InterruptedException异常,因此,在调用wait()方法时,需要将它放入try…catch代码块中。此外,使用该方法时还需要把它放到一个同步代码段中,否则会出现如下异常:
"java.lang.IllegalMonitorStateException: current thread not owner"
这些方法是不是就可以实现线程间的通信了呢?下面将通过多线程同步的模型: 生产者和消费者问题来说明怎样通过程序解决多线程间的通信问题。
具体步骤
下面这个程序演示了多个线程之间进行通信的具体实现过程。程序中用到了4个类,其中ShareData类用来定义共享数据和同步方法。在同步方法中调用了wait()方法和notify()方法,并通过一个信号量来实现线程间的消息传递。
package com.src.cn;
class ShareData{
private char c;
private boolean have = false;//信号量
public synchronized void putsharechar(char src){//同步方法
if(have){//如果产品还未消费,则生产者等待
try{
wait();//生产者等待
}catch(Exception e){
e.printStackTrace();
}
}
this.c=src;
have=true;//标记为已经生产
notify();//通知消费者已经生产,可以消费
}
public synchronized char getsharechar(){//同步方法
if(!have){//如果产品还未生产,则消费者等待
try{
wait();//消费者等待
}catch(Exception e){
e.printStackTrace();
}
}
have = false;//标记为已经消费
notify();//通知需要生产
return this.c;
}
}
class Producer extends Thread{//生产者线程
private ShareData s;
Producer(ShareData src){
this.s=src;
}
public void run(){
for(char ch='A';ch<='D';ch++){
try{
Thread.sleep((int)(Math.random()*3000));
}catch(Exception e){
e.printStackTrace();
}
s.putsharechar(ch);//放入仓库
System.out.println(ch+"is produced by Producer");
}
}
}
class Consumer extends Thread{//消费者线程
private ShareData s;
Consumer(ShareData src){
this.s=src;
}
public void run(){
char ch;
do{
try{
Thread.sleep((int)(Math.random()*3000));
}catch(Exception e){
e.printStackTrace();
}
ch=s.getsharechar();//从仓库取出
System.out.println(ch+"is consumed by Consumer");
}while(ch!='D');
}
}
public class Demo {
public static void main(String args[]){
ShareData sd=new ShareData();
new Consumer(sd).start();
new Producer(sd).start();
}
}