黑马程序员——利用生产者和消费者模式讨论notify()方法的运用

本文通过生产者消费者模式探讨了在多线程环境下,notify()方法如何唤醒等待线程。实验表明,notify()会唤醒等待队列中最先等待的线程,但若唤醒的线程无法继续执行,会重新进入等待,可能导致所有线程等待,造成程序停滞。
摘要由CSDN通过智能技术生成
------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

    当使用多线程来同时运行多个任务时,可以通过锁来同步多个任务的行为,从而使得一个任务不会干涉另一个任务的资源。也就是说,如果多个任务在交替着访问内存中的某项资源,可以通过锁来控制同一时刻只有一个任务可以访问该资源。为了使任务可以协作,我们可以使用wait()和notify()机制来控制。

     这里,我们用生产者和消费者的例子来说明:

/*
	定义资源类,类中包括生产set和消费out的方法
*/
class Resource{
	private String name;
	private  int count = 1;
	private boolean flag = false;
	public synchronized void set(String name){
		while(flag)
			try{
			 wait();
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		this.name = name+count++;
		System.out.println(Thread.currentThread().getName()+"生产"+this.name);
		flag = true;
		notifyAll();//此处若改为notify()方法,可能会使所有线程都陷入等待状态
	}
	public synchronized void out(){
		while(!flag)
			try{
			wait();
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		
		System.out.println("..."+Thread.currentThread().getName()+"消费...."+this.name);
		flag = false;
		notifyAll();
	}
}
//定义生产者类,实现Runnable接口的run方法
class Producer implements Runnable{
	private Resource res;
	Producer(Resource res){
		this.res = res;
	}
	public void run(){
		while(true)
			res.set("产品");
	}

}
//定义消费者类,实现Runnable接口的run方法
class Consumer implements Runnable{
	private Resource res;
	Consumer(Resource res){
		this.res = res;
	}
	public void run(){
		while(true)
			res.out();
	}
}
public class Noname1{
	public static void main(String[] args){
		Resource res = new Resource();
		Producer pro = new Producer(res);
		Consumer con = new Consumer(res);
		//创建两个生产者线程
		Thread t0 = new Thread(pro);
		Thread t1 = new Thread(pro);
		//创建两个消费者线程
		Thread s2 = new Thread(con);
		Thread s3 = new Thread(con);
		//分别启动线程
		t0.start();
		t1.start();
		s2.start();
		s3.start();
		
	}
}
     

       上面的例子定义了两个生产者和两个消费者

生产者生产一个产品,消费者消费一个,它

以很和谐地工作。运行结果如图。

        我们在set和out方法里使用的唤醒等待线程

的方法是notifyAll(),我们知道,如果使用notify()

的话,由于每次只能唤醒单个线程,所以最终可

能导致所有线程都陷入等待状态。

       可是,问题是,如果同时有多个线程处于等

待状态,notify()方法会唤醒哪个线程呢?为此,

我查阅了一些资料,有的说是随机唤醒一个线程,

有的说是唤醒最先等待的线程,还有的对此问题

避而不谈,下面,我们通过具体实例来验证,还

是使用的生产者与消费者的例子。


      为了验证上面的问题,我们将上面的代码进行了一些改变

class Resource{
	private String name;
	private  int count = 1;
	private boolean flag = false;
	public synchronized void set(String name){
		while(flag)
			try{
			 wait();
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		this.name = name+count++;
		System.out.println(Thread.currentThread().getName()+"生产"+this.name);
		flag = true;
		notify();
	}
	public synchronized void out(){
		while(!flag)
			try{
			wait();
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		
		System.out.println("..."+Thread.currentThread().getName()+"消费...."+this.name);
		flag = false;
		notify();
	}
}
class Producer implements Runnable{
	private Resource res;
	Producer(Resource res){
		this.res = res;
	}
	public void run(){
		while(true)
			res.set("产品");
	}

}
class Consumer implements Runnable{
	private Resource res;
	Consumer(Resource res){
		this.res = res;
	}
	public void run(){
		while(true)
			res.out();
	}
}
public class ProducerDemo{
	public static void main(String[] args){
		Resource res = new Resource();
		Producer pro = new Producer(res);
		Consumer con = new Consumer(res);
		//创建两个生产者线程
		Thread t0 = new Thread(pro);
		Thread t1 = new Thread(pro);
                //创建两个消费者线程
		Thread t2 = new Thread(con);
		Thread t3 = new Thread(con);
	
		 t0.start();
		 try{
			 Thread.sleep(10);
			 }catch(InterruptedException e){
 				e.printStackTrace();
 			}
 		t1.start();
 		//让主线程停止10ms,目的是使两个生产者线程都陷入等待
		 try{
			 Thread.sleep(10);
 			}catch(InterruptedException e){
				 e.printStackTrace();
 			}
		t2.start();
		try{
			Thread.sleep(10);
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		t3.start();
		
	}
}

      其中,其他内容不变,只有主方法中插入了一些sleep()方法,目的是使各个线程按照我们自己的意愿去运行。我们先看运行结果如图。下面我们来分析:

      首先,语句 t0.start()启动t0线程,生产出产品1,t0陷入等待;

      接着t1线程启动,由于flag被置为true,所以,不生产产品,t1直接等待;

     然后t2线程启动,消费产品1,将flag置为flase,唤醒一个线程,t2等待;

     根据输出,我们可以看到t2唤醒的是线程是t0,所以t0执行,生产产品2,唤醒一个线程,t0再次等待;

     根据输出,t0唤醒的线程并没有执行,而是直接进入等待,接着执行t3,消费产品2,唤醒一个线程,t3等待;

     根据输出,t3唤醒的线程也没有执行,直接陷入等待,自此,所有的线程都在等待状态,所以程序停滞不前。

    

     为了更好的说明问题,我们通过画图来解释:


       根据结果我们可以推论,用来存储等待中的线程的容器为一队列,即履行“先进先出”的原则。如上图所示,从下至上为进入等待状态线程的顺序。当执行notify()方法时,也是从下至上的顺序。可以看到,最终,t0,t1,t2,t3四个线程都进入等待状态。

















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值