基础篇:线程间的协作之生产者与消费者(十)

生产者与消费者的代码实现,这个套路基本上和上篇文章一个样,所以我就不对代码多做解释了;

之所以写这篇文章是为了介绍ReentrantLock 以及方便后面的一篇采用JDK提供的队列来实现生产者与消费者的代码来与之做比较;


先看输出********************************************************************************

开始做食物...
食物做完了!...
开始吃食物...
食物吃完了!...
开始做食物...
食物做完了!...
开始吃食物...
食物吃完了!...
开始做食物...
食物做完了!...
开始吃食物...
食物吃完了!...
开始做食物...

******************************************************************************************


//餐厅
class Restaurant{
	public Food food = null;//餐厅里的食物默认是没有的
	public Provider provider = null;
	public Consumer comsumer = null;

	public void setProvider( Provider provider){
		this.provider= provider;
	}
	public void setConsumer( Consumer consumer){
		this.comsumer= consumer;
	}
	
	//用单例,保证所有顾客都是在同一家餐厅
	private Restaurant() {}
	private static final Restaurant restaurant = new Restaurant();
	public static Restaurant getInstance(){return restaurant;}
	
}

//食物提供者(厨师)
class Provider{
	//在这家餐厅工作
	private Restaurant res =  null;
	
	public Provider( Restaurant res ) {
		this.res = res;
	}
	
	public void fry() throws InterruptedException{//炒菜
		while( !Thread.currentThread().isInterrupted() ){
			synchronized (this) {
				//如果当前还有食物没有被消费完,则继续等待
				while( res.food!=null ){
					wait();
				}
			}
			
			synchronized (res.comsumer) {
				System.out.println("开始做食物...");
				TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
				res.food= new Food();
				System.out.println("食物做完了!...");
				//让顾客开始吃食物
				res.comsumer.notifyAll();
			}
		}
	}
}

//食物消费者(顾客)
class Consumer{
	//在这家餐厅就餐
	private Restaurant res = null;
	
	public Consumer( Restaurant res ) {
		this.res = res;
	}
	//吃食物方法
	public void eat() throws InterruptedException{
		while( !Thread.currentThread().isInterrupted() ){
			synchronized (this) {
				//如果当前没有食物可用,则继续等待
				while(res.food==null){
					wait();
				}
			}
			synchronized (res.provider) {
				System.out.println("开始吃食物...");
				TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));//吃食物时间
				res.food=null;
				System.out.println("食物吃完了!...");
				//让厨师继续做食物
				res.provider.notifyAll();
			}
		}
	}
}


//经典生产者与消费者演示(不采用队列的普通实现)
	//考虑这样一个场景:顾客在餐厅点菜后,厨师开始炒菜,厨师炒完菜后送给顾客吃,顾客吃完又通知厨师炒菜...周而复始...
	//这个场景就是典型的生产者(厨师)与消费者(顾客)
	public static void producer(){
		ExecutorService exec = Executors.newCachedThreadPool();
		Restaurant res = Restaurant.getInstance();
		final Consumer consumer = new Consumer(res);
		final Provider provider = new Provider(res);
		res.setProvider(provider);
		res.setConsumer(consumer);
		
		//启动顾客线程,顾客要消费
		exec.execute(new Runnable() {
			public void run() {
				try {
					consumer.eat();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		
		//启动厨师线程,厨师要生产
		exec.execute(new Runnable() {
			public void run() {
				try {
					provider.fry();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
	}


Ok,不做代码解释,和上篇一样,接下来我们主要看下怎么利用ReentrantLock来实现生产者与消费者,让我们修改下代码:

//餐厅
class Restaurant{
	public Food food = null;//餐厅里的食物默认是没有的
	public Provider provider = null;
	public Consumer comsumer = null;
//	演示变体,利用Lock来进行协作,需要增加两把锁以及两个条件
	public ReentrantLock providerLock = new ReentrantLock();
	public ReentrantLock consumerLock = new ReentrantLock();
	public Condition providerCondition = providerLock.newCondition();
	public Condition consumerCondition = consumerLock.newCondition();
	
	public void setProvider( Provider provider){
		this.provider= provider;
	}
	public void setConsumer( Consumer consumer){
		this.comsumer= consumer;
	}
	
	//用单例,保证所有顾客都是在同一家餐厅
	private Restaurant() {}
	private static final Restaurant restaurant = new Restaurant();
	public static Restaurant getInstance(){return restaurant;}
	
}


//食物提供者(厨师)
class Provider{
	//在这家餐厅工作
	private Restaurant res =  null;
	
	public Provider( Restaurant res ) {
		this.res = res;
	}
	
	public void fry() throws InterruptedException{//炒菜
		while( !Thread.currentThread().isInterrupted() ){
//			开始演示使用Lock来进行协作
			res.providerLock.lock();
			while( res.food!=null ){
				res.providerCondition.await();
			}
			res.providerLock.unlock();
			
			res.consumerLock.lock();
			System.out.println("开始做食物...");
			TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
			res.food= new Food();
			System.out.println("食物做完了!...");
			//让顾客开始吃食物
			res.consumerCondition.signalAll();
			res.consumerLock.unlock();
		}
	}
}

//食物消费者(顾客)
class Consumer{
	//在这家餐厅就餐
	private Restaurant res = null;
	
	public Consumer( Restaurant res ) {
		this.res = res;
	}
	//吃食物方法
	public void eat() throws InterruptedException{
		while( !Thread.currentThread().isInterrupted() ){
//			开始演示使用Lock来进行协作
			res.consumerLock.lock();
			while(res.food==null){
				res.consumerCondition.await();
			}
			res.consumerLock.unlock();
			
			res.providerLock.lock();
			System.out.println("开始吃食物...");
			TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));//吃食物时间
			res.food=null;
			System.out.println("食物吃完了!...");
			//让厨师继续做食物
			res.providerCondition.signalAll();
			res.providerLock.unlock();
		}
	}
}

稍作解释: 这里主要利用ReentrantLock的 lock()与unLock() 来进行加解锁 , 通过调用它的newCondition()方法来获得一个对象监视器,该监视器拥有await(0与signalAll()等方法, 和Object的wait()以及notifyALL()的功能是一样的!


多线程的基础篇到这里就结束了,你要知道的是,在实际工作中,肯定是不需要你自己来写什么notify和wait之类的,这太困难了,得写一堆难看的代码,那么接下来,我们就来学学怎么使用JDK中的一些好用的工具类,来帮助我们轻而易举的实现复杂的多线程编程问题;




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值