现在的位置: 首页 > 综合 > 正文

多线程之生产消费问题

2018年06月05日 ⁄ 综合 ⁄ 共 2366字 ⁄ 字号 评论关闭

问题:一个仓库最多容纳6个产品,制造商现在要制造20件产品存入仓库,消费者要从仓库取出20件产品来消费,制造商生产产品和消费者消费产品的速度很可能不一样!

/**
 * 定义仓库
 * @author Liao
 */
class SyncStack{
	
	/*用数组来表示仓库的容量*/
	char[] data = new char[6];
	/*定义数组下标的标示*/
	int cnt = 0;
	
	/**
	 * 把生产出来的产品放入仓库中
	 * 这里使用线程同步的关键字synchronized
	 * 执行push()方法的时候就不能执行pop()操作!!!!
	 * @param ch 模拟产品的字符
	 */
	public synchronized void push(char ch){
		
		/*如果仓库已满*/
		while (cnt == data.length){//这是一个while,也就是说如果为true的话,将会一直执行
			
			/*如果仓库满了的话,我们就使得生产线程进入等待状态【注:这里不能通过sleep()来控制哈,谁知道消费者啥时候来取,谁知道睡多长时间呢?所以要使用wait()进行等待】*/
			try {
				this.wait();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		/*通知正在等待的线程进入就绪状态(可能不会立即执行),即使没有线程在等待也不会报错,所以一定要加上这句,否则正在等待的线程可能会陷入阻塞*/
		this.notify();
		
		/*把产品出入仓库*/
		data[cnt] = ch;
		/*数组下标加一*/
		cnt ++;
		
		System.out.printf("生产了: %c\n", ch);
		System.out.printf("容器中现在共有%d个字符!\n\n", cnt);	
	}
	
	/**
	 * 消费者从仓库中取出产品
	 * 这里也要使用线程同步
	 * 执行pop()方法的时候就不能执行push()方法
	 * @throws  
	 */
	public synchronized char pop() {
		
		char ch;
		
		/*如果仓库中没有产品*/
		while (cnt == 0){
			
			/*如果仓库中没有产品,我们就让消费线程进入等待状态*/
			try {
				this.wait();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		/*通知正在等待的线程进入就绪状态(可能不会立即执行),即使没有线程在等待也是不会报错的,所以一定要加上这句,否则正在等待的线程可能会陷入阻塞*/
		this.notify();
		
		/*取出最上面的产品*/
		ch = data[cnt - 1];
		/*数组的下标要减去1*/
		cnt --;
		
		System.out.printf("取出:  %c\n", ch);
		System.out.printf("容器中现在共有%d个字符!\n\n", cnt);
		
		return ch;
	}
}

/**
 * 定义生产者
 * @author Liao
 */
class Producer implements Runnable{

	/*定义仓库【生产者生产处产品就把产品放入仓库中】*/
	public SyncStack s = null;
	
	/*构造函数,把仓库传进来*/
	public Producer(SyncStack s) {
		
		this.s = s;
	}
	
	/**
	 * 生产操作
	 */
	public void run() {
		
		char ch;
		
		/*生产20个产品*/
		for (int i=0; i<20; i++){
			/*一个字符模拟一个产品*/
			ch = (char) ('a' + i);
			/*把制造出来的产品放入仓库中*/
			s.push(ch);
		}
	}

}

/**
 * 定义消费者
 * @author Liao
 */
class Consumer implements Runnable{

	/*定义仓库【消费者从仓库中取出产品】*/
	public SyncStack s = null;
	
	/*构造函数*/
	public Consumer(SyncStack s) {
		this.s = s;
	}
	
	/*消费者消费产品*/
	public void run() {
		
		/*遍历消费20个产品*/
		for (int i=0; i<20; i++){
			
			/*从仓库中取出一个产品*/
			s.pop();
			
			/*每隔500ms取出一个产品*/
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
}

/**
 * 测试类
 * @author Liao
 *
 */
public class ProducerConsumerTest {

	
	public static void main(String[] args) {
		
		/*创建仓库*/
		SyncStack ss = new SyncStack();
		/*创建生产者*/
		Producer producer = new Producer(ss);
		/*创建消费者*/
		Consumer consumer = new Consumer(ss);
		
		/*创建生产者线程*/
		Thread pThread = new Thread(producer);
		/*创建消费者线程*/
		Thread cThread = new Thread(consumer);
		
		/*启动两个线程*/
		pThread.start();
		cThread.start();
	}

}

总结:

1:a.wait():将执行a.wait()的线程进入阻塞状态,让出CPU的控制权,释放对a的锁定。

2:a.notify():叫醒正在等待的线程,使其进入就绪状态,需要注意的是,此时即使没有线程在等待,调用这个方法也是不会出错的。

3:a.notifyAll():叫醒其他所有因为执行了wait()而陷入阻塞的线程。

4:不能使用sleep(XXX),和设置优先级来控制哪一个线程先执行,因为这些都不能是线程立即进入运行状态,而是进入就绪状态。

注:notify()和notifyAll()不是叫醒调用他们的当前线程,而是叫醒其他因为调用wait()而陷入阻塞的线程。

抱歉!评论已关闭.