package com.njust.test.learn;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class LockCacheDemo
{
    private Map<String, Object> cacheMap = new HashMap<>();
    
    public static void main(String[] args)
    {
        LockCacheDemo lockCacheDemo = new LockCacheDemo();
        
        String[] array = {"11", "22", "11", "44", "11"};
        List<String> list = Arrays.asList(array);
        for (String s : list)
        {
            final String key = "key." + s;
            new Thread(() -> {
                while (true)
                {
                    lockCacheDemo.loadData(key);
                    //printLog(String.format("read data:%s with key:%s", key, data));
                }
            }).start();
        }
    }
    
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    
    /**
     * 获取缓存数据
     * 1.如果是第一次进来，要从db加载
     * 2.如果非首次进来，就是读取的缓存
     */
    private Object loadData(String key)
    {
        readWriteLock.readLock().lock();
        
        Object data = null;
        try
        {
            printLog("<--- try to loadData with key:" + key);
            sleep(1000);
            data = cacheMap.get(key);
            
            if (data == null)
            {
                try
                {
                    //1.double check:因为可能两个读者同时进来了，一个先获得写锁，另一个后获得写锁，可能重新readFromDB
                    data = cacheMap.get(key);
                    
                    //2.要获取写锁，必须先释放读锁
                    readWriteLock.readLock().unlock();
                    readWriteLock.writeLock().lock();
                    
                    if (data == null)
                    {
                        data = readFromDB(key); //模拟从数据库加载
                        cacheMap.put(key, data);
                    }
                    /*else
                    {
                        printLog(".......double check save your time, with key" + key);
                    }*/
                }
                finally
                {
                    //拥有写锁要获取读锁，可以先获取读锁(会发生降级)
                    readWriteLock.readLock().lock();
                    readWriteLock.writeLock().unlock();
                }
            }
        }
        finally
        {
            readWriteLock.readLock().unlock();
        }
        
        printLog("---> end loadData:" + data + " with key:" + key);
        return data;
    }
    
    private Object readFromDB(String key)
    {
        String data = "readFromDB." + key;
        sleep(2000);
        printLog("=====> readFromDB with key" + key);
        return data;
    }
    
    private void sleep(int ms)
    {
        try
        {
            Thread.sleep(ms);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
    
    private void printLog(String msg)
    {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
        String dateStr = simpleDateFormat.format(new Date());
        System.out.println("[" + dateStr + "] " + Thread.currentThread().getName() + " " + msg);
    }
    
}

@@ -1468,156 +1468,124 @@
     
-try%0A                %7B%0A                    //1.double check:%E5%9B%A0%E4%B8%BA%E5%8F%AF%E8%83%BD%E4%B8%A4%E4%B8%AA%E8%AF%BB%E8%80%85%E5%90%8C%E6%97%B6%E8%BF%9B%E6%9D%A5%E4%BA%86%EF%BC%8C%E4%B8%80%E4%B8%AA%E5%85%88%E8%8E%B7%E5%BE%97%E5%86%99%E9%94%81%EF%BC%8C%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%90%8E%E8%8E%B7%E5%BE%97%E5%86%99%E9%94%81%EF%BC%8C%E5%8F%AF%E8%83%BD%E9%87%8D%E6%96%B0readFromDB%0A                    data = cacheMap.get(key
+//2.%E8%A6%81%E8%8E%B7%E5%8F%96%E5%86%99%E9%94%81%EF%BC%8C%E5%BF%85%E9%A1%BB%E5%85%88%E9%87%8A%E6%94%BE%E8%AF%BB%E9%94%81%0A                readWriteLock.readLock().unlock();%0A                readWriteLock.writeLock().lock(
 );%0A 
@@ -1591,36 +1591,52 @@
                 
+%0A   
     
+         try
 %0A               
@@ -1640,159 +1640,138 @@
     
-    //2.%E8%A6%81%E8%8E%B7%E5%8F%96%E5%86%99%E9%94%81%EF%BC%8C%E5%BF%85%E9%A1%BB%E5%85%88%E9%87%8A%E6%94%BE%E8%AF%BB%E9%94%81%0A                    readWriteLock.readLock().unlock();%0A                    readWriteLock.writeLock().lock();%0A                    
+%7B%0A                    //1.double check:%E5%9B%A0%E4%B8%BA%E5%8F%AF%E8%83%BD%E4%B8%A4%E4%B8%AA%E8%AF%BB%E8%80%85%E5%90%8C%E6%97%B6%E8%BF%9B%E6%9D%A5%E4%BA%86%EF%BC%8C%E4%B8%80%E4%B8%AA%E5%85%88%E8%8E%B7%E5%BE%97%E5%86%99%E9%94%81%EF%BC%8C%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%90%8E%E8%8E%B7%E5%BE%97%E5%86%99%E9%94%81%EF%BC%8C%E5%8F%AF%E8%83%BD%E9%87%8D%E6%96%B0readFromDB%0A                    data = cacheMap.get(key);
 %0A   

Create LockCacheDemo.java