wait、notify、notifyAll

本文介绍如何使用Java的wait和notify方法实现生产者消费者问题。通过synchronized关键字确保线程安全,生产者将数据放入队列,消费者从中获取数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注意:这些方法属于Object,而不属于Thread。

每一个对象除了有一个锁之外,还有一个等待队列(wait set),当一个对象刚创建的时候,他的等待队列是空的。

我们可以利用这些方法来解决“生产者和消费者的问题”。

wait方法呢,是在当前线程锁住对象的锁后,才调用该对象的wait方法的。即在同步代码块中或者同步方法中进行调用的。调用后,该对象的等待队列中就有了一个所在线程,那个线程进入等待状态,此时,只有该对象调用notify方法,才可以把那个线程从队列里面拿出来,使这个线程成为可运行线程。

notifyAll方法就是把该对象等待队列里面的所有线程唤醒,成为可运行线程。

 

生产者和消费者问题的简单实现:


public class ProductorConsumerProblem {

 /**
  * @param args
  */
 public static void main(String[] args) {
   ThreadQueue queue=new ThreadQueue();
   Productor productor=new Productor(queue);
   Consumer consumer=new Consumer(queue);
   productor.start();
   consumer.start();

 }

}

/*生产者类*/
class Productor extends Thread{
 ThreadQueue queue;//等待队列
 public Productor(ThreadQueue q){
  queue=q;
 }
 public void run(){
   for(int i=1;i<10;i++){
     queue.put(i);//把数据放入等待队列中
     System.out.println("Productor puts "+i);
   }
 }
}

class Consumer extends Thread{
 ThreadQueue queue;
 public Consumer(ThreadQueue q){
  queue=q;
 }
 
 public void run(){
     for(int i=1;i<10;i++){
      System.out.println("Consumer gets "+queue.get());//从等待队列中取出数据并显示
     }
 }
}

class ThreadQueue{
 int value;
 boolean isFull=false;//false表示是空的
 //下面的get和put都是用的是this这个监视器,所以可用notify和wait进行等待与唤醒
 public synchronized void put(int i){
  if(!isFull){//如果队列是空的,那么就放入数据,把队列的标志设为true(非空),然后调用notify方法,唤醒get的wait
        this.value=i;
        isFull=true;
        notify();//当这个是第一次调用时等待队列里面没有等待的线程,那是不是要判断等待对列是否为空才判断执不执行呢,没必要,因为这个耗费不大,就相当于多执行一条语句,所以没必要判断,如果要写判断语句,那么代码还复杂些,所以这个影响不大的情况下,我们没必要判断。
  }
  try{
   wait();//如果队列是非空的,那么就不要放入数据,就处于等待,一直等待消费者取走数据并调用notify方法
  }catch(Exception e){
   e.printStackTrace();
  }
  }
 
 public synchronized int get(){
  if(!isFull){
   try{
    wait();//如果队列是空的,那么就等待,不能取数据
   }catch(Exception e){
    e.printStackTrace();
   }
  }
  notify();//如果非空,那么取走数据并调用notify方法唤醒put的等待,设置变量为空。注意,因为return后方法就不再继续了,所以要在return之前设置要做的事
  isFull=false;
  return value;
 }
}



 

如果一个类是线程安全的,那么我们编写线程来调用那个类的方法等的时候,不会出现不同步,死锁等问题,我们要让类是安全的,可以被多线程调用,我们在那个类的方法或者代码块上就要加上关键字synchronized等处理线程同步等安全问题。这些是类设计者要考虑的问题,比如消费者和生产者那个问题中的ThreadQueue就要考虑线程安全问题。所以,设计类是很重要的,比如要有封装性,如果可以多线程访问,要考虑线程安全问题等等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值