Lock myLock = new ReentrantLock(); myLock.lock();//獲取鎖 try{ //do something }finally{ //釋放鎖。須要放在finally子句內,不然拋異常後,鎖未被釋放,其餘線程則會永遠被阻塞 myLock.unlock(); }
讀寫鎖分爲讀鎖和寫鎖。多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥。 java
Java中讀寫鎖有個接口java.util.concurrent.locks.ReadWriteLock,也有具體的實現ReentrantReadWriteLock。 數據庫
在實際開發中,最好在能用讀寫鎖的狀況下使用讀寫鎖,而不要用普通鎖,以求更好的性能。 緩存
public class SimpleCacheDemo{ private Map<String, Object> cache = new HashMap<String, Object>(); private ReadWriteLock rwlock = new ReentrantReadWriteLock(); public Object getData(String key){ rwlock.readLock().lock(); Object obj = null; try{ obj = cache.get(key); if(obj == null){ rwlock.readLock().unlock(); rolock.wirteLock().lock(); try{ if(obj == null){ obj = queryDB(key); if(obj != null){ cache.put(key, obj); return obj; } } }finally{ rwlock.writeLock().unlock(); } rwlock.readLock().lock(); } }finally{ rwlock.readLock().unlock(); } return obj; } //從數據庫查出值 public Object queryDB(key){ //todo return null; } }
條件變量都實現了java.util.concurrent.locks.Condition接口,條件變量的實例化是經過一個Lock對象上調用newCondition()方法來獲取的,這樣,條件就和一個鎖對象綁定起來了。所以,Java中的條件變量只能和鎖配合使用,來控制併發程序訪問競爭資源的安全。 安全
條件變量的出現是爲了更精細控制線程等待與喚醒,在Java5以前,線程的等待與喚醒依靠的是Object對象的wait()和notify()/notifyAll()方法,這樣的處理不夠精細。 併發
Condition將Object監視器方法wait()、notify()、notifyAll()分解成大相徑庭的對象,以便經過這些對象與任意Lock實現組合使用。 對應的方法是:await()、signal() 、signalAll() 。import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Java線程:併發協做-生產者消費者模型 */ public class ProducerConsumer { public static void main(String[] args) { Godown godown = new Godown(30); Consumer c1 = new Consumer(50, godown); Consumer c2 = new Consumer(20, godown); Consumer c3 = new Consumer(30, godown); Producer p1 = new Producer(10, godown); Producer p2 = new Producer(10, godown); Producer p3 = new Producer(50, godown); Producer p4 = new Producer(10, godown); Producer p5 = new Producer(70, godown); c1.start(); c2.start(); c3.start(); p1.start(); p2.start(); p3.start(); p4.start(); p5.start(); } } /** * 倉庫 */ class Godown { public static final int max_size = 100; //最大庫存量 public int curnum; //當前庫存量 private final Lock lock = new ReentrantLock(); private final Condition connProduce = lock.newCondition(); private final Condition connConsume = lock.newCondition(); public Godown() { } public Godown(int curnum) { this.curnum = curnum; } /** * 生產指定數量的產品 * * @param neednum */ public void produce(int neednum) { lock.lock(); try{ //測試是否須要生產 while (neednum + curnum > max_size) { System.out.println("要生產的產品數量" + neednum + "超過剩餘庫存量" + (max_size - curnum) + ",暫時不能執行生產任務!"); try { //當前的生產線程等待 connProduce.await(); } catch (InterruptedException e) { e.printStackTrace(); } } //知足生產條件,則進行生產,這裏簡單的更改當前庫存量 curnum += neednum; System.out.println("已經生產了" + neednum + "個產品,現倉儲量爲" + curnum); //喚醒在此對象監視器上等待的全部消費線程 connConsume.signalAll(); }finally{ lock.unlock(); } } /** * 消費指定數量的產品 * * @param neednum */ public void consume(int neednum) { lock.lock(); try{ //測試是否可消費 while (curnum < neednum) { try { //當前的消費線程等待 connConsume.await(); } catch (InterruptedException e) { e.printStackTrace(); } } //知足消費條件,則進行消費,這裏簡單的更改當前庫存量 curnum -= neednum; System.out.println("已經消費了" + neednum + "個產品,現倉儲量爲" + curnum); //喚醒在此對象監視器上等待的全部生產線程 connProduce.signalAll(); }finally{ lock.unlock(); } } } /** * 生產者 */ class Producer extends Thread { private int neednum; //生產產品的數量 private Godown godown; //倉庫 Producer(int neednum, Godown godown) { this.neednum = neednum; this.godown = godown; } public void run() { //生產指定數量的產品 godown.produce(neednum); } } /** * 消費者 */ class Consumer extends Thread { private int neednum; //生產產品的數量 private Godown godown; //倉庫 Consumer(int neednum, Godown godown) { this.neednum = neednum; this.godown = godown; } public void run() { //消費指定數量的產品 godown.consume(neednum); } }