併發設計模式---生產者/消費者模式

1、什麼是生產者消費者模式?

生產者/消費者模式是爲了解耦消費者和生產者而產生的,其原理很是地簡單。總的來講就是生產者和消費者之間不直接通訊,而是藉助一個第三方(一般是阻塞隊列),第三方也成爲臨界資源,同一時間只容許一條線程對其進行操做。java

  • 一、當臨界資源滿了,生產者必須阻塞等待;
  • 二、當臨界資源爲空,消費者必須阻塞等待,通知生產者生產;

2、使用簡單的notify/wait機制實現

全部的註釋都寫在代碼中,在這裏咱們模仿在水桶中存水和取水的過程:bash

Main.javaide

package com.wokao66.consumerProvider;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 測試
 * @author: huangjiawei
 * @since: 2018年4月3日
 * @version: $Revision$ $Date$ $LastChangedBy$
 */
public class Main {

	public static void main(String[] args) {
		/**
		 * 新建一個水桶,存放全部的水,剛開始水桶是空的,容量爲5L
		 */
		List<Water> waterList = new ArrayList<>(5);
		ExecutorService executors = Executors.newFixedThreadPool(10);
		WaterProvider provider = new WaterProvider(waterList);
		WaterConsumer consumer = new WaterConsumer(waterList);
		executors.execute(provider);
		executors.execute(consumer);
	}
}
複製代碼

WaterProvider.java測試

package com.wokao66.consumerProvider;

import java.util.List;

/**
 * 往桶裏加水的生產者
 * @author: huangjiawei
 * @since: 2018年4月3日
 * @version: $Revision$ $Date$ $LastChangedBy$
 */
public class WaterProvider implements Runnable {

	/**
	 * 這是咱們的水桶(10L)
	 */
	private List<Water> waterList = null;

	/**
	 * 初始化水桶,也就是緩衝區
	 */
	public WaterProvider(List<Water> waterList) {
		this.waterList = waterList;
	}

	@Override
	public void run() {
		/**
		 * 循環任務,也就是這個任務會執行屢次,沒有明確的break語句或者異常,該任務不會終止
		 */
		while (true) {
			/**
			 * 這裏得到waterList的鎖,以前說過notify、wait的使用必須先得到鎖
			 */
			synchronized (waterList) {
				/**
				 * 判斷是否是滿了,滿了就不生產了
				 */
				while (waterList.size() == 5) {
					try {
						/**
						 * 這裏將所釋放掉waterList的鎖
						 */
						waterList.wait();
					} catch (InterruptedException e) {}
				}
				/**
				 * 若是尚未滿,那麼就加1L水進去,加進去以前
				 */
				waterList.add(new Water());
				System.err.println("生產了1L水,如今水桶有:" + waterList.size() + "L水");
				try {
					/**
					 * sleep方法是不會釋放鎖的
					 */
					Thread.sleep(1000);
				} catch (InterruptedException e) {}
				/**
				 * 我通知全部的消費者來消費
				 */
				waterList.notifyAll();
			}
		}
	}
}
複製代碼

WaterConsumer.javaui

package com.wokao66.consumerProvider;

import java.util.List;

/**
 * 往桶裏取水的消費者
 * @author: huangjiawei
 * @since: 2018年4月3日
 * @version: $Revision$ $Date$ $LastChangedBy$
 */
public class WaterConsumer implements Runnable {

	private List<Water> waterList;

	public WaterConsumer(List<Water> waterList) {
		this.waterList = waterList;
	}

	@Override
	public void run() {
		/**
		 * 循環任務,也就是這個任務會執行屢次,沒有明確的break語句或者異常,該任務不會終止
		 */
		while (true) {
			/**
			 * 得到鎖
			 */
			synchronized (waterList) {
				/**
				 * 證實沒有水能夠消費
				 */
				while (waterList.isEmpty()) {
					try {
						/**
						 * 釋放鎖
						 */
						waterList.wait();
					} catch (InterruptedException e) {}
				}
				/**
				 * 每次我都移動第一個元素
				 */
				waterList.remove(0);
				System.err.println("消費了1L水,如今水桶有:" + waterList.size() + "L水");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {}
				/**
				 * 通知生產者生產
				 */
				waterList.notifyAll();
			}
		}
	}
}
複製代碼

Water.javathis

package com.wokao66.consumerProvider;

/**
 * 水這種類型
 * @author: huangjiawei
 * @since: 2018年4月3日
 * @version: $Revision$ $Date$ $LastChangedBy$
 */
public class Water {

	/**
	 * 單位L
	 */
	private String unit;

	public String getUnit() {
		return unit;
	}

	public void setUnit(String unit) {
		this.unit = unit;
	}
}   
複製代碼

執行結果:spa

生產了1L水,如今水桶有:1L水
生產了1L水,如今水桶有:2L水
消費了1L水,如今水桶有:1L水
消費了1L水,如今水桶有:0L水
生產了1L水,如今水桶有:1L水
生產了1L水,如今水桶有:2L水
消費了1L水,如今水桶有:1L水
消費了1L水,如今水桶有:0L水
生產了1L水,如今水桶有:1L水
消費了1L水,如今水桶有:0L水
生產了1L水,如今水桶有:1L水
生產了1L水,如今水桶有:2L水
生產了1L水,如今水桶有:3L水
生產了1L水,如今水桶有:4L水
生產了1L水,如今水桶有:5L水
消費了1L水,如今水桶有:4L水
消費了1L水,如今水桶有:3L水
消費了1L水,如今水桶有:2L水
消費了1L水,如今水桶有:1L水
複製代碼

執行結果可能會不一致,但數據正確便可!線程

相關文章
相關標籤/搜索