ReentrantLock簡單介紹和使用ReentrantLock實現生產者消費者模式


/**
 * 1,ReentrantLock和synchronized都是可重入鎖,Reentrant的本意就是“可重入的”。可重入鎖顧名思義,就是在擁有鎖的情況下可以調用其它需要本鎖的方法或者代碼塊
 * (同一個鎖對象)
 *,2,synchronized只能實現非公平鎖,ReentrantLock可以實現公平鎖和非公平鎖。公平鎖或者非公平鎖,顧名思義就是線程獲取鎖的順序是否和加鎖的順序一致。ReentrantLock
 * 默認的構造方法創建的是非公平鎖,ReentrantLock(true)創建的是公平鎖。因爲公平鎖是將線程放到一個隊列裏面按次序進行調度(FIFO),因此性能比較低。
 * 3,ReentrantLock的鎖必須手動釋放,即調用unlock()方法釋放鎖,否則一直阻塞。釋放鎖的代碼最好在finally代碼塊中進行,因爲ReentrantLock發生異常時不會釋放鎖,而synchronized
 * 修飾的代碼塊發生異常時可以釋放鎖。
 * 4,synchronized與wait()/notify()、notifyAll()方法相結合可以實現線程間的通信。ReentrantLock和Condition配合能實現類似的功能,並且功能更強大。
 * ReentrantLock和Condition的組合可以喚醒某個特定的線程,而synchronized喚醒哪個線程,是不確定的。
 * 5,synchronized鎖對象的wait()方法相當於Condition的await()方法,會釋放鎖,線程進入阻塞狀態。
 *  synchronized鎖對象的wait(long)方法相當於Condition類的await(long)方法,多少秒之後才進入阻塞狀態並釋放鎖。
 *  synchronized鎖對類的notify()方法相當於Condition的signal()方法,notifyAll()方法相當於Condition類的signalAll()方法,喚醒等待的線程
 * 6,參考博客:https://www.cnblogs.com/qlqwjy/p/10130454.html,感謝作者
 *
 */
public class ReentrantLockTest {
   List<Integer> list=new ArrayList<Integer>();
   //創建鎖
	private  Lock lock=new ReentrantLock();
	
	private Condition consumerCd = lock.newCondition();
	private Condition producterCd = lock.newCondition();
	
	/**
	 * 創建兩個消費者線程,兩個生產者線程
	 */
	public void f1() {
		Thread consumer1=new Thread(new Runnable() {
			@Override
			public void run() {
				consumeMethod();
			}
		},"消費者1");
		
		Thread consumer2=new Thread(new Runnable() {
			@Override
			public void run() {
				consumeMethod();
				
			}
		},"消費者2");
		
		Thread producter1=new Thread(new Runnable() {
			@Override
			public void run() {
				productMethod();
				
			}
		},"生產者1");
		
		Thread producter2=new Thread(new Runnable() {
			@Override
			public void run() {
				productMethod();
				
			}
		},"生產者2");
		
		consumer1.start();
		consumer2.start();
		producter1.start();
		producter2.start();
		
	}
	
	/**
	 * 消費方法
	 * 如果數組長度大於0,則消費者線程消費一個元素。否則給生產者線程發信號喚醒生產者進行生產,自己等待。
	 */
	public void consumeMethod(){
		try {
			lock.lock();
			while(true){
				if(list.size()>0){
					System.out.println(Thread.currentThread().getName()+"消費了一個產品:"+list.get(0));
					list.remove(0);
				}else{
					//signal()方法要在await()方法之前執行,因爲await()方法是阻塞的,一旦await()方法先執行,signal()方法就不能及時執行。
					producterCd.signal();
					consumerCd.await();
				}
			}
			
		} catch (Exception e) {
			
		}finally{
			lock.unlock();
		}
	}
	/**
	 * 生產方法
	 * 如果數組長度等於0,生產者線程則生產一個元素,並給消費者線程發信號喚醒消費者進行消費,自己等待
	 */
	public void productMethod(){
		try {
			lock.lock();
			Random random=new Random();
			while(true){
				if(list.size()==0){
					int value=random.nextInt(100);
					list.add(value);
					System.out.println(Thread.currentThread().getName()+"生產了一個產品:"+value);
					consumerCd.signal();
				}else{
					producterCd.await();
				}
			}
			
		} catch (Exception e) {
			
		}finally{
			lock.unlock();
		}
		
	}

	public static void main(String[] args) {
		ReentrantLockTest reentrantLockTest=new ReentrantLockTest();
		reentrantLockTest.f1();
	}
}

控制檯輸出(部分數據):
 

生產者2生產了一個產品:61
消費者1消費了一個產品:61
生產者1生產了一個產品:27
消費者2消費了一個產品:27
生產者2生產了一個產品:41
消費者1消費了一個產品:41
生產者1生產了一個產品:33
消費者2消費了一個產品:33
生產者2生產了一個產品:40
消費者1消費了一個產品:40
生產者1生產了一個產品:43
消費者2消費了一個產品:43
生產者2生產了一個產品:47
消費者1消費了一個產品:47
生產者1生產了一個產品:85
消費者2消費了一個產品:85
生產者2生產了一個產品:13
消費者1消費了一個產品:13
生產者1生產了一個產品:66
消費者2消費了一個產品:66
生產者2生產了一個產品:98
消費者1消費了一個產品:98
生產者1生產了一個產品:91
消費者2消費了一個產品:91
生產者2生產了一個產品:72
消費者1消費了一個產品:72
生產者1生產了一個產品:11
消費者2消費了一個產品:11
生產者2生產了一個產品:91
消費者1消費了一個產品:91
生產者1生產了一個產品:78
消費者2消費了一個產品:78
生產者2生產了一個產品:25
消費者1消費了一個產品:25
生產者1生產了一個產品:5
消費者2消費了一個產品:5
生產者2生產了一個產品:6
消費者1消費了一個產品:6
生產者1生產了一個產品:20
消費者2消費了一個產品:20
生產者2生產了一個產品:93
消費者1消費了一個產品:93
生產者1生產了一個產品:31
消費者2消費了一個產品:31
生產者2生產了一個產品:12
消費者1消費了一個產品:12
生產者1生產了一個產品:33
消費者2消費了一個產品:33
生產者2生產了一個產品:25
消費者1消費了一個產品:25
生產者1生產了一個產品:57
消費者2消費了一個產品:57
生產者2生產了一個產品:96
消費者1消費了一個產品:96
生產者1生產了一個產品:9
消費者2消費了一個產品:9
生產者2生產了一個產品:87
消費者1消費了一個產品:87
生產者1生產了一個產品:48
消費者2消費了一個產品:48
生產者2生產了一個產品:41
消費者1消費了一個產品:41
生產者1生產了一個產品:62
消費者2消費了一個產品:62
生產者2生產了一個產品:4
消費者1消費了一個產品:4
生產者1生產了一個產品:63

聲明:隨手一寫,並不嚴謹,切勿作爲參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章