讀寫鎖:讀寫鎖分爲讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥,這是由JVM本身控制的,咱們只要上好相應的鎖便可。若是代碼是隻讀數據,能夠不少人同時讀,但不能同時寫,那就須要上讀鎖;若是代碼是修改數據,只能有一我的在寫,且不能在寫的時候讀,就須要上寫鎖。總之,讀的時候上讀鎖,寫的時候上寫鎖。java
- import java.util.HashMap;
- import java.util.Map;
- import java.util.concurrent.locks.ReadWriteLock;
- import java.util.concurrent.locks.ReentrantReadWriteLock;
- 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;
- }
- }
程序運行的結果:面試
從運行結果能夠看到,當一個線程寫的時候,其它的線程不容許寫;而讀的時候,容許多個線程同時讀,且讀到的數據是一致的。數據庫
在Hibernate中會有代碼1-2 這樣的代碼:緩存
- User user = session.load(id,User.class);
- User user = session.get(id,User.class);
那麼代碼1-2 與 1-3 有什麼區別呢?session
代碼1-2 ,無論數據庫中有沒有記錄,它都返回一個user對象,它是一個代理(是user的子類,能夠被當作user用),是一個假的,不是一個真正的user對象。以下圖:ide
代碼1-3 ,是直接到數據庫中把對象給「抓」出來,若是沒有「抓」到,返回的值是NULL(空)。看看下面的這道面試題:spa
- import java.util.HashMap;
- import java.util.Map;
- import java.util.concurrent.locks.ReadWriteLock;
- import java.util.concurrent.locks.ReentrantReadWriteLock;
- public class CacheDemo {
- private Map<String, Object> cache = new HashMap<String, Object>();//定義緩存
- public static void main(String[] args) {
- }
- private ReadWriteLock rwl = new ReentrantReadWriteLock();//定義一個讀寫鎖
- /*
- 取數據的方法,檢查內部是否有key這個數據,若是有,直接傳遞給程序;沒有,去數據庫查,
- 查到以後存到緩存的內存中。 下次,再有程序找該數據時,直接將緩存中的數據傳給程序,不須要訪問數據庫
- */
- public Object getData(String key){
- rwl.readLock().lock();//首先都上讀鎖*(均可以讀),加鎖,實現多個線程的訪問
- Object value = null;//注意:在try{}catch(){}中不能定義變量
- try{
- value = cache.get(key);//在cache中取數據
- 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;
- }
- }
注意代碼線程
- if(value==null){//當其它的線程檢查不爲空,就不用再寫
- value = "aaaa";//實際是去queryDB();
- }
當其它的線程檢查緩存中有數據時,就再也不進行寫的操做。代理