线程协作与生产者消费者问题

本文深入探讨了多线程环境下线程协作的重要性,特别是通过wait-notify机制实现的生产者和消费者问题解决方案。以面包店为例,详细解析了如何使用Java的线程同步机制确保线程间的有效协作,避免共享资源的数据错误。
摘要由CSDN通过智能技术生成

线程协作

在多线程开发中,为避免共享资源数据错误,常使用互斥(synchronized)机制实现多线程对共享资源的访问同步。然而,当线程间需要相互提供支持的情况下,仅有互斥机制是不够的,这就是线程协作机制起作用的时候了。

  • 线程协作是多线程互斥同步的基础上,使线程之间依照一定条件,有目的、有计划地交互协同工作,这是一种较高级的线程同步方式。

  • Java提供了一个精心设计的线程间通信机制即wait-notify机制,通过该机制可以实现线程协作。

  • wait-notify机制是通过使用wait()、notify()和notifyAll()三个方法来实现的。

    这三个方法均定义在Object类中,是final修饰的实例方法。
    这三个方法必须在synchronized代码中调用,而且只有通过锁对象才能调用这三个方法。

  • wait()方法
    通过当前同步锁调用该方法的线程在当前同步锁下进入等待状态,直到其他线程通过相同的同步锁调用notify( )或者notifyAll()方法。

  • notify( )
    通过当前同步锁调用该方法,唤醒在当前同步锁下等待的线程中的一个结束等待。

  • notifyAll()
    通过当前同步锁调用该方法,唤醒在当前同步锁下等待的所有线程结束等待。

生产者和消费者问题

在多线程程序设计中,生产者和消费者问题是典型的需要线程协作的场景。这类问题一般存在两类线程和一个共享数据资源,一类是提供共享数据的线程即生产者,另一类消耗共享数据的线程即消费者。这类问题具有以下特点:

  • 一方面为防止数据错误,生产者和消费者是互斥的,任何一方访问共享数据时,另一方不能访问共享数据;
  • 另一方面生产者和消费互相需要对方。生产者不能无限制提供数据,当共享数据达到最大量时,需要让消费者消耗数据。消费者也不能无限制消耗数据,当已无共享数据,需要让生产者提供数据。

案例-面包店

说明

面包店的柜橱用来存放面包,面包师傅负责将烤好面包放到柜橱中,店面伙计负责将柜橱中的面包售出。存在以下两种问题:

  1. 柜橱放满了,新面包没处放;
  2. 柜橱空了,但是面包仍在销售中。

解决问题的办法

  • 师傅检查橱柜,若橱柜未满放入面包,同时通知伙计有面包卖,若橱柜满师傅暂停工作,直到收到伙计通知可以放面包了。
  • 伙计检查橱柜,若橱柜未空销售面包,同时通知师傅可以放面包,若橱柜空伙计暂停工作,直到收到师傅通知有面包卖。

代码实现

开发面包柜(共享数据资源)

//面包柜
public class Cupboard {
	
	private int count;//面包数量
	private int size;//面包容量
	
	public Cupboard(int size ){
		this.size=size;
	}
	
	//放入一个面包,该方法是同步方法,同步锁为this
	public synchronized void add(){
		while(this.isFull()) {
			System.out.println(Thread.currentThread().getName()+":柜内面包数:"+count+",已满!等待中......");
			try {
				this.wait();//在当前同步锁对象(this)下等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		count++;
		System.out.println(Thread.currentThread().getName()+":放入一个面包,柜内面包数:"+count);
		this.notifyAll();//唤醒在当前同步锁对象(this)下等待的所有线程
		Thread.yield();//让步,给其它线程以运行机会
	}
	
	//取出一个面包,该方法是同步方法,同步锁为this
	public synchronized void remove(){
		while(this.isEmpty()) {
			System.out.println(Thread.currentThread().getName()+":柜内面包数:"+count+",已空!等待中......");
			try {
				this.wait();//在当前同步锁对象(this)下等待
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		count--;
		System.out.println(Thread.currentThread().getName()+":取出一个面包,柜内面包数:"+count);
		this.notifyAll();//唤醒在当前同步锁对象(this)下等待的所有线程
		Thread.yield();//让步,给其它线程以运行机会
	}
	
	//面包柜是否为空
	public boolean isEmpty(){
		return count<1;
	}
	
	//面包柜是否已满
	public boolean isFull(){
		return count>=size;
	}

}

测试代码

public class Test {

	public static void main(String[] args) {
		
		final Cupboard cupboard = new Cupboard(5);//创建面包柜,容量为5个面包
		
		//创建三个面包师线程和三个伙计线程,并启动。每个面包师烤一百个面包,每个伙计销售一百个面包。
		for(int i=1;i<=3;i++) {
			
			//面包师线程
			new Thread("面包师"+i) {
				public void run() {
					for(int i=0;i<100;i++) {
						cupboard.add();
					}
				}
			}.start();
			
			//伙计线程
			new Thread("伙计"+i) {
				public void run() {
					for(int i=0;i<100;i++) {
						cupboard.remove();
					}
				}
			}.start();
			
		}

	}

}

运行结果截图如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值