一、使用自定義鎖實作生成--消費模型
下面我們使用上節自定義的鎖實作一個簡單的生產--消費模型,代碼如下:
package com.ruigege.LockSourceAnalysis6;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
public class Test {
final static NonReentrantLock lock = new NonReentrantLock();
final static Condition notFull = lock.newCondition();
final static Condition notEmpty = lock.newCondition();
final static Queue<String> queue = new LinkedBlockingQueue<String>();
final static int queueSize = 10;
public static void main(String[] args) {
Thread producer = new Thread(new Runnable() {
public void run() {
// 獲取獨占鎖
lock.lock();
try {
// (1)如果佇列滿了,則等待
while(queue.size() == queueSize) {
notEmpty.await();
}
// (2)添加元素到佇列
queue.add("ele");
// (3)喚醒消費執行緒
notFull.signalAll();
}catch(Exception e) {
e.printStackTrace();
}finally {
// 釋放鎖
lock.unlock();
}
}
});
Thread consumer = new Thread(new Runnable() {
public void run() {
// 獲取獨占鎖
lock.lock();
try {
// 佇列空,則等待
while(0 == queue.size()) {
notFull.await();
}
// 消費一個元素
String ele = queue.poll();
// 喚醒生產執行緒
notEmpty.signalAll();
}catch(Exception e) {
e.printStackTrace();
}finally {
// 釋放鎖
lock.unlock();
}
}
});
// 啟動執行緒
producer.start();
consumer.start();
}
}
如上代碼首先創建了一個NonReentrantLock的一個物件lock,然后呼叫lock.newCondition創建了兩個條件變數,用來進行生產者和消費者執行緒之間的同步, 在main函式中,首先創建了producer生產執行緒,在執行緒內部首先呼叫lock.lock()獲取獨占鎖,然后判斷當前佇列是否已經滿了,如果滿了則呼叫notEmpty.await()阻塞掛起當前執行緒,需要注意的是,這里使用了while而不是if是為了避免虛假喚醒,如果佇列不滿則直接向佇列里面添加元素,然后呼叫notFull.signalAll()喚醒所有因為消費元素而被i阻塞的消費執行緒,最后釋放獲取的鎖,
二.使用自定義鎖實作一個消費模型
package com.ruigege.LockSourceAnalysis6;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class NonReentrantLockME implements Lock,java.io.Serializable{
// 內部幫助類
private static class Sync extends AbstractQueueSynchronizer {
// 是否鎖已經被持有
protected boolean isHeldExclusively() {
return getState() == 1;
}
// 如果state為0,則嘗試獲取鎖
public boolean tryAcquire(int acquires) {
assert acquires == 1;
if(compareAndSetState(0,1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// 嘗試釋放鎖,設定state為0
protected boolean tryRelease(int release) {
assert releases == 1;
if(getState() == 0) {
throw new IllegalMonitorStateException();
}
setExclusiveOwnerThread(null);
setState(0);
return true;
}
// 提供條件變數介面
Condition newConditon() {
return new ConditionObject();
}
}
// 創建一個Sync來做具體的作業
private final Sync sync = new Sync();
public void lock() {
sync.acquire(1);
}
public boolean tryLock() {
return sync.tryAcquire(1);
}
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newConditon();
}
public boolean isLocked() {
return sync.isHeldExclusively();
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock(long timeout,TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1,unit.toNanos(timeout));
}
}
使用NonReentrantLock創建一個實體,然后呼叫newCondition方法來生成兩個條件變數來進行生產者和消費者執行緒之間的同步, 在main函式中,首先創建了producer生產執行緒,在執行緒內部先獲取了獨占鎖,然后看一下佇列是否滿了,如果滿了,那就阻塞當前執行緒,如果沒有滿直接在佇列中加入佇列中,這里使用的while回圈而不是使用if陳述句,這是為了避免虛假喚醒,然后呼叫notFull.sinalAll()喚醒所有因為消費元素而被阻塞的消費執行緒,最后釋放了鎖, 在main函式中創建了consumer執行緒,先獲取獨占鎖,先判斷佇列有沒有元素,如果沒有元素,那么就先掛起當前執行緒,這里使用了while是為了避免虛假喚醒,如果佇列中不為空,那么就拿出一個元素,然后喚醒因為佇列滿而被阻塞的生產執行緒,最后釋放獲取的鎖,
三、原始碼:
所在包:com.ruigege.ConcurrentListSouceCodeAnalysis5 https://github.com/ruigege66/ConcurrentJavaCSDN:https://blog.csdn.net/weixin_44630050 博客園:https://www.cnblogs.com/ruigege0000/ 歡迎關注微信公眾號:傅里葉變換,個人賬號,僅用于技術交流 
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/266217.html
標籤:Java
