1. 程式人生 > >Lock和condition實現生產者,消費者模型

Lock和condition實現生產者,消費者模型

package ThreadLearn;
/**
 * 面試題:寫一個固定容量同步容器,擁有put和get方法,以及getCount方法,
 * 能夠支援2個生產者執行緒以及10個消費者執行緒的阻塞呼叫
 * 
 * 使用wait和notify/notifyAll來實現
 * 
 * 使用Lock和Condition來實現
 * 對比兩種方式,Condition的方式可以更加精確的指定哪些執行緒被喚醒
 */
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class T021_02Mycontainer2<T> {
	final private LinkedList<T> lists = new LinkedList<>();
	final private int MAX = 10; //最多10個元素
	private int count = 0;
	
	private Lock lock = new ReentrantLock();
	private Condition producer = lock.newCondition();
	private Condition consumer = lock.newCondition();
	
	public void put(T t) {
		try {
			lock.lock();
			while(lists.size() == MAX) { //想想為什麼用while而不是用if?
				producer.await();
			}
			
			lists.add(t);
			++count;
			consumer.signalAll(); //通知消費者執行緒進行消費
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public T get() {
		T t = null;
		try {
			lock.lock();
			while(lists.size() == 0) {
				consumer.await();
			}
			t = lists.removeFirst();
			count --;
			producer.signalAll(); //通知生產者進行生產
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
		return t;
	}
	
	public static void main(String[] args) {
		T021_02Mycontainer2<String> c = new T021_02Mycontainer2<>();
		//啟動消費者執行緒
		for(int i=0; i<10; i++) {
			new Thread(()->{
				for(int j=0; j<5; j++) System.out.println(c.get());
			}, "c" + i).start();
		}
		
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		//啟動生產者執行緒
		for(int i=0; i<2; i++) {
			new Thread(()->{
				for(int j=0; j<25; j++) c.put(Thread.currentThread().getName() + " " + j);
			}, "p" + i).start();
		}
	}
}