Java多线程--生产者与消费者问题

说明

Java中,线程之间的通信主要是由java.lang.Object类提供的waitnotifynotifyAll这3个方法来完成:

①对象的wait方法被调用后,线程进入对象的等待队列中,并释放对象锁,其它线程可以竞争使用此对象锁;sleep方法使得一个线程进入睡眠状态,但是线程所占有的资源并没有释放。

②当对象的notify方法被调用,该方法会从对象的等待队列中随机取出一个线程来唤醒;notifyAll是唤醒等待队列中所有线程,这些线程会与其它正在执行的线程共同竞争对象锁。

③wait、notifynotifyAll这3个方法只能出现在synchronized作用的范围内。当多个线程等待同一对象,而它们等待等待的条件不同时,应该使用notifyAll方法。notifyAll会导致性能下降,因为不必要的线程也会被唤醒。而notify唤醒的线程有可能不是所期望的线程。


生产者与消费者问题

这里,将使用某类资源(用类Goods表示)的线程称为消费者Consumer,产生同类资源的线程称为Producer。要想使得Consumer和Producer能够协同工作,则它们应该遵循如下规则:

(1)只要缓冲区buffer有空间,生产者Producer就可向其中存放资源;当缓冲区buffer已满时,则让生产者Producer等待,放弃自己已获取的对象锁,进入等待队列;

(2)只要缓冲区中有资源可用,消费者Consumer就可以从buffer中取出资源;当buffer为空时,则让Consumer等待,放弃自己已获取的对象锁,进入等待队列;

(3)Producer和Consumer不能同时读、写buffer。所以对buffer进行操作的方法increase(生产资源)和decrease(消费资源)均需要使用synchronized进行同步。


/**
 * Goods类,表示共享资源
 */
package com.hh.Producer.Consumer;

public class Goods {
	private final int SIZE = 5;
	private int buffer = 0;

	/**
	 * 共享资源增加
	 */
	public synchronized int increase() {
		if (buffer < SIZE) {
			++buffer;
			notify(); // 通知消费者可以消费
		} else {
			try {
				wait(); // 生成者线程等待,直到消费者线程发出notify通知
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return buffer;
	}

	/**
	 * 共享资源减少
	 */
	public synchronized int decrease() {
		if (buffer > 0) {
			--buffer;
			notify(); // 通知生产者可以生产
		} else {
			try {
				wait(); // 消费者线程等待,直到生产者线程发出notify通知
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return buffer;
	}

	public int getGoodsSize() {
		return SIZE;
	}

}


/**
 * Producer类,模拟生产者线程
 */
package com.hh.Producer.Consumer;

public class Producer implements Runnable {

	private Goods goods;

	public Producer(Goods goods) {
		this.goods = goods;
	}

	@Override
	public void run() {
		while (true) {
			int goodsCount = goods.increase();
			if (goodsCount != goods.getGoodsSize()) {
				System.out.println("生产者生产了一件商品,目前商品数:" + goodsCount);
			} else {
				System.out.println("商品已满,生产者等待");
			}
			try {
				Thread.sleep((int) (Math.random() * 1000));
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

/**
 * Consumer类,模拟消费者
 */
package com.hh.Producer.Consumer;

public class Consumer implements Runnable {

	private Goods goods;

	public Consumer(Goods goods) {
		this.goods = goods;
	}

	@Override
	public void run() {
		while (true) {
			int goodsCount = goods.decrease();
			if (goodsCount != 0) {
				System.out.println("消费者消费了一件商品,目前商品数:" + goodsCount);
			} else {
				System.out.println("商品已空,消费者等待");
			}
			try {
				Thread.sleep((int) (Math.random() * 1000));
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}

/**
 * 测试生产者Producer与消费者Consumer线程之间的通信
 */
package com.hh.Producer.Consumer;

public class TestMain {
	
	public static void main(String[] args) {
		Goods goods = new Goods();
		Producer producer = new Producer(goods);
		Consumer consumer = new Consumer(goods);

		new Thread(producer).start();
		new Thread(consumer).start();
	}

}

注意:是在共享资源Goods类中进行wait和notify操作,并不是在Producer或者Consumer类中。

对于这样的问题,一定要自己动手写示例代码,这样才能较好的理解线程之间的通信问题。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值