Java多线程通信-利用传统的线程通信wait(),notify()方法实现“生产者消费者模式”

想利用传统的线程通信wait(),notify(),notifyAll()方法,必须依赖于同步监听器的存在,也就是说,对于synchronized修饰的同步方法,因为该类的默认实例(this)就是同步监听器,所以可以在同步方法中直接调用这三个方法;对于使用synchronized修饰的同步代码块,同步监听器是synchronized后括号的对象,所以必须使用该对象调用这三个方法。这三个方法的作用分别是:

wait():导致当前线程等待,直到其它线程调用该同步监听器的notify()方法或notifyAll()方法来唤醒该线程。

notify():唤醒在该同步监听器上等待的单个线程。如果有不至一个线程在该同步监听器上等待,则任意选择唤醒其中一个线程。

notifyAll():唤醒在该同步监听器上等待的所有线程。

下面通过利用传统的线程通信来实现一个典型的“生产者消费者模式”:

1.同一时间内只能有一个生产者生产

2.同一时间内只能有一个消费者消费

3.生产者生产的同时消费者不能消费 

4.消费者消费的同时生产者不能生产 

5.共享空间空时消费者不能继续消费

6.共享空间满时生产者不能继续生产




/**
 * @author newuser
 *	馒头类,有一个编号,用来标记是第几个馒头
 */
class ManTou {
	private int num;

	public ManTou(int num) {
		super();
		this.num = num;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 * 重写toString()方法
	 */
	@Override
	public String toString() {
		return "ManTou [num=" + num + "]";
	}
}

/**
 * @author newuser
 *	商店类
 */
class Store {
//	BlockingQueue<ManTou> manTouQueues = new ArrayBlockingQueue<ManTou>(10);
	//定义一个ManTou数组,做共享空间,用来存放ManTou类对象,也就是用来存储馒头
	private ManTou[] manTous=new ManTou[10];
	//定义一个下标,用来标记数组的存放位置
	int index=0; 

	/**
	 * @param manTou
	 * 	生产一个馒头manTou,synchronized是同步方法的修饰符,这里同步方法的作用等同于lock
	 */
	public synchronized void put(ManTou manTou) {
		//如果下标超出数组的长度,则把线程推到阻塞状态,不能进行生产了
		if (index>=manTous.length) {
			try {
				wait();//把线程推到阻塞状态
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//否则(未超出数组的长度),把馒头加到数组里面
		manTous[index]=manTou;
		System.out.println(Thread.currentThread().getName()+" 生产:"+manTous[index]);
		index++;
		
		//唤醒其他线程,这里主要是唤醒消费线程,表示可以进行消费了
		notifyAll();
	}

	/**
	 * @return ManTou
	 * 	卖出了一个馒头,synchronized是同步方法的修饰符,这里同步方法的作用等同于lock
	 */
	public synchronized ManTou poll() {
		ManTou mTou = null;
		//如果下标小于或等于0,也就是库存里没有库存了,则把本线程推到阻塞状态,不能进行消费了
		if (index<=0) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		//库存下标减一
		index--;
		System.out.println(Thread.currentThread().getName()+" 消费:"+manTous[index]);
		
		//唤醒其他线程,这里主要是唤醒生产线程,表示可以进行生产费了
		notifyAll();
		return mTou;
	}

}

/**
 * @author newuser
 *	生存线程类
 */
class ProduceThreat implements Runnable {

	//定义一个Store对象
	private Store myStore;

	//本类构造器
	public ProduceThreat(Store myStore) {
		super();
		this.myStore = myStore;
	}

	//重写Runnable的run()方法,也就是线程的执行体
	public void run() {
		//生产30次
		for (int i = 0; i < 30; i++) {
			ManTou manTou = new ManTou(i);
			myStore.put(manTou);
		}
	}
}

/**
 * @author newuser
 *	消费者线程类
 */
class ConsumerThreat implements Runnable {

	//定义一个Store对象
	private Store myStore;

	//本类构造器
	public ConsumerThreat(Store myStore) {
		super();
		this.myStore = myStore;
	}

	//重写Runnable的run()方法,也就是线程的执行体
	public void run() {
		//消费30次
		for (int i = 0; i < 30; i++) {
			myStore.poll();
		}
	}
}

public class ProdeceConsumerTest {

	public static void main(String[] args) {
		
		//创建一个Store对象
		Store myStore=new Store();
		
		//把Store对象分别传给两个线程
		ProduceThreat p=new ProduceThreat(myStore);
		ConsumerThreat c=new ConsumerThreat(myStore);
		
		//创建两个子线程
		Thread pThread=new Thread(p);
		Thread cThread=new Thread(c);
		
		//开始两个线程
		pThread.start();
		cThread.start();
	}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值