Java 5中提供了另一種實現線程同步或互斥的機制,即使用Lock。Lock比傳統執行緒模式中的synchronized方式更加物件導向。
互斥鎖–Lock(ReentrantLock)
所謂互斥鎖, 指的是一次最多隻能有一個線程持有的鎖. 在jdk1.5之前, 我們通常使用synchronized機制控制多個線程對共用資源的訪問. 而現在, Lock提供了比synchronized機制更廣泛的鎖定操作, Lock和synchronized機制的主要區別:
synchronized機制提供了對與每個對象相關的隱式監視器鎖的訪問, 並強制所有鎖擷取和釋放均要出現在一個塊結構中, 當擷取了多個鎖時, 它們必須以相反的順序釋放. synchronized機制對鎖的釋放是隱式的, 只要線程啟動並執行代碼超出了synchronized語句區塊範圍, 鎖就會被釋放. 而Lock機制必須顯式的調用Lock對象的unlock()方法才能釋放鎖, 這為擷取鎖和釋放鎖不出現在同一個塊結構中, 以及以更自由的順序釋放鎖提供了可能。
讀寫鎖–ReadWriteLock(ReentrantReadWriteLock)
讀寫鎖:分為讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥。換句話說讀取鎖允許多個reader線程同時持有, 而寫入鎖最多隻能有一個writter線程持有。
讀寫鎖的使用場合: 讀取共用資料的頻率遠大於修改共用資料的頻率, 在上述場合下, 使用讀寫鎖控制共用資源的訪問, 可以提高並發效能。
package com.huang.test;import java.util.HashMap;import java.util.Map;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;/** * 讀寫鎖的妙用 * 簡單緩衝 的原理 * @author wuseyukui * */public class CacheDemo { private ReadWriteLock lock = new ReentrantReadWriteLock(); private Map<String, Object> cache = new HashMap<String, Object>(); public static void main(String[] args) { } /** * 簡單,通俗 * 缺點:只有寫的時候需要同步(互斥),多線程讀資料的時候不需要同步,影響效率 * @param key * @return */// public synchronized Object getData(String key) {// Object obj = cache.get(key);// if (obj == null) {// obj = "aaa";// 實際是去查詢DB// }// // return obj;// } /** * 效率高, 多線程讀資料時用讀鎖可並發,寫資料時用寫鎖互斥。 * @param key * @return */ public synchronized Object getData(String key) { lock.readLock().lock(); Object obj = null; try { obj = cache.get(key); if (obj == null) { lock.readLock().unlock(); lock.writeLock().lock();// ① try { // 為了代碼的嚴禁縝密 // 假設有三個線程到了代碼①處,線程1成功獲得寫鎖,另外兩個線程被阻塞。 // 當線程1執行到②,釋放了寫鎖,另外兩個線程就有機會擷取到寫鎖,進行DB操作,此時obj已經不為空白,不需要再查詢DB if (obj == null) { obj = "aaa";// 實際是去查詢DB } } catch (Exception e) { e.printStackTrace(); } finally { lock.writeLock().unlock();// ② } lock.readLock().lock(); } } catch (Exception e) { e.printStackTrace(); } finally { lock.readLock().unlock(); } return obj; }}