直接给出第一版程序,如下:
public class CacheDemo
{
private Map<String,Object> data=new HashMap<String,Object>();
public Object getValue(String key)
{
Object value=data.get(key);
if(value==null)
{//说明缓存中没有数据,那么需要去数据库中获取,然后放入缓存
value="数据库中获取的数据";
data.put(key,vakue);
}
return value;
}
}
上面的版本即是最简单的缓存,核心在于:现在缓存集合中找数据,如果没找到再去数据库中获取。上面是无法进行多线程应用的,所以可以讲方法改成synchronized。然而这并不是最佳的处理多线程的方式,因为获取数据的过程只有2步:读缓存,(读数据库和写缓存)。那么可以考虑使用读写锁机制,新版本如下:
public class CacheDemo
{
private Map<String, Object> cache = new HashMap<String, Object>();
private ReadWriteLock rwl = new ReentrantReadWriteLock();
publicObject getData(String key)
{
// 首先上读锁
rwl.readLock().lock();
// 首先从缓存中获取
Object value = null;
try
{
Thread.sleep(1000);
value = cache.get(key);
if (value == null)
{
// 如果缓存中没有数据,那么就从数据库中获取
// 但此时需要上写锁,只需要让一个进程进行写数据
// 首先去除读锁,然后加上写锁
rwl.readLock().unlock();
rwl.writeLock().lock();
try
{
//此处是亮点,防止多线程运行到上一步,某个线程写完数据后
//别的线程就需要看是否有数据再决定是否进行写操作
//在写之前再读一次,防止最开始的线程都进行写操作
value = cache.get(key);
// 第一个线程写完后,防止后面的线程再次写数据
if (value == null)
{
System.out.println("有线程写数据........");
value = "数据库中获取";
// 将数据放入缓存
cache.put(key, value);
System.out.println("数据写完了.......");
}
} finally
{
rwl.writeLock().unlock();
}
rwl.readLock().lock();
}
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
} finally
{
rwl.readLock().unlock();
}
return value;
}
}
转载于:https://blog.51cto.com/xuliangjun/1748357