JAVA 併發程式設計-讀寫鎖之模擬快取系統(十一)
阿新 • • 發佈:2019-02-02
在多執行緒中,為了提高效率有些共享資源允許同時進行多個讀的操作,但只允許一個寫的操作,比如一個檔案,只要其內容不變可以讓多個執行緒同時讀,不必做排他的鎖定,排他的鎖定只有在寫的時候需要,以保證別的執行緒不會看到資料不完整的檔案。這時候就需要使用讀寫鎖。
/** * 簡單讀寫鎖demo * @author hejingyuan * */ public class ReadWriteLockTest { public static void main(String[] args) { final Queue3 q3 = new Queue3(); //建立幾個執行緒 for(int i=0;i<3;i++) { new Thread(){ public void run(){ while(true){ q3.get(); } } }.start(); new Thread(){ public void run(){ while(true){ q3.put(new Random().nextInt(10000)); } } }.start(); } } } class Queue3{ private Object data = null;//共享資料,只能有一個執行緒能寫該資料,但可以有多個執行緒同時讀該資料 //讀寫鎖 ReadWriteLock rwl = new ReentrantReadWriteLock(); //讀資料 public void get(){ rwl.readLock().lock(); try { System.out.println(Thread.currentThread().getName() + " be ready to read data!"); Thread.sleep((long)(Math.random()*1000)); System.out.println(Thread.currentThread().getName() + "have read data :" + data); } catch (InterruptedException e) { e.printStackTrace(); }finally{ rwl.readLock().unlock(); } } //寫資料 public void put(Object data){ rwl.writeLock().lock(); try { System.out.println(Thread.currentThread().getName() + " be ready to write data!"); Thread.sleep((long)(Math.random()*1000)); this.data = data; System.out.println(Thread.currentThread().getName() + " have write data: " + data); } catch (InterruptedException e) { e.printStackTrace(); }finally{ rwl.writeLock().unlock(); } } }
執行結果:
Thread-0 be ready to readdata!
Thread-2 be ready to readdata!
Thread-2have read data:null
Thread-0have read data:null
Thread-1 be ready towrite data!
Thread-1 have write data:1021
Thread-1 be ready towrite data!
Thread-1 have write data:2887
看到這裡不免有人會問,既然讀的時候可以多人訪問,那麼為什麼還要加讀鎖呢?
答:當然要加鎖了,否則在寫時去讀,可能不正確-(寫的時候不能去讀)
讀寫鎖-模擬快取系統實現:
public class CacheDemo { private Map<String, Object> cache = new HashMap<String, Object>(); public static void main(String[] args) { } //定義讀寫鎖 private ReadWriteLock rwl = new ReentrantReadWriteLock(); //讀資料,使用讀鎖 public Object getData(String key){ //新增讀鎖 rwl.readLock().lock(); Object value = null; try{ value = cache.get(key); if(value == null){ //釋放讀鎖 rwl.readLock().unlock(); //加上寫鎖 rwl.writeLock().lock(); try{ //假設三個執行緒同時去獲取寫鎖,我們知道只有第一個執行緒能夠獲取 //那麼其他兩個執行緒只有等了,如果第一個執行緒按流程執行完後,剛才的兩個執行緒可以得到寫鎖了, //然後接著就可以修改資料了(賦值).所以加上判斷! if(value==null){//為什麼還要判斷? value = "aaaa";//實際是去queryDB(); } }finally{ //釋放寫鎖 rwl.writeLock().unlock(); } rwl.readLock().lock(); } }finally{ rwl.readLock().unlock(); } return value; } }
總結:
讀寫鎖的作用為,當我們加上寫鎖時,其他執行緒被阻塞,只有一個寫操作在執行,當我們加上讀鎖後,它是不會限制多個讀執行緒去訪問的。也就是get和put之間是互斥的,put與任何執行緒均為互斥,但是get與get執行緒間並不是互斥的。其實加讀寫鎖的目的是同一把鎖的讀鎖既可以與寫鎖互斥,讀鎖之間還可以共享。