标签:多线程 缓存系统 cache reentrantreadwritelo 读写锁
简单地缓存系统:当有线程来取数据时,如果该数据存在我的内存中,我就返回数据;如果不存在我的缓存系统中,那么就去查数据库,返回数据的同时保存在我的缓存中。
其中涉及到读写问题:当多个线程执行读操作时(都加读锁),如果有数据返回;如果没有数据时,则让第一个读的线程,进行获取数据,然后进行写操作,这时需要第一个线程先释放掉读锁然后加写锁。第一个写完后,在家读锁,其他线程使用时判断,如果存在该数据,在直接过去读取不用加写锁。
API上缓存例子如下:
class CachedData { Object data; volatile boolean cacheValid; ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); void processCachedData() { rwl.readLock().lock(); if (!cacheValid) { // Must release read lock before acquiring write lock rwl.readLock().unlock(); rwl.writeLock().lock(); // Recheck state because another thread might have acquired // write lock and changed state before we did. if (!cacheValid) { data = ... cacheValid = true; } // Downgrade by acquiring read lock before releasing write lock rwl.readLock().lock(); rwl.writeLock().unlock(); // Unlock write, still hold read } use(data); rwl.readLock().unlock(); } }
ReentrantReadWriteLock
此类具有以下属性:
此类不会将读取者优先或写入者优先强加给锁访问的排序。但是,它确实支持可选的公平 策略。
如果保持写入锁,或者有一个等待的 writer 线程,则试图获得公平读取锁(非重入地)的线程将会阻塞。直到当前最旧的等待 writer 线程已获得并释放了写入锁之后,该线程才会获得读取锁。当然,如果等待 writer 放弃其等待,而保留一个或更多 reader 线程为队列中带有写入锁自由的时间最长的 waiter,则将为那些 reader 分配读取锁。
试图获得公平写入锁的(非重入地)的线程将会阻塞,除非读取锁和写入锁都自由(这意味着没有等待线程)。(注意,非阻塞
ReentrantReadWriteLock.ReadLock.tryLock()
和
ReentrantReadWriteLock.WriteLock.tryLock()
方法不会遵守此公平设置,并将获得锁(如果可能),不考虑等待线程)。
此锁允许 reader 和 writer 按照
ReentrantLock
的样式重新获取读取锁或写入锁。在写入线程保持的所有写入锁都已经释放后,才允许重入 reader 使用它们。
此外,writer 可以获取读取锁,但反过来则不成立。在其他应用程序中,当在调用或回调那些在读取锁状态下执行读取操作的方法期间保持写入锁时,重入很有用。如果 reader 试图获取写入锁,那么将永远不会获得成功。
重入还允许从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。但是,从读取锁升级到写入锁是不可能的。
读取锁和写入锁都支持锁获取期间的中断。
Condition
支持
写入锁提供了一个 Condition
实现,对于写入锁来说,该实现的行为与
ReentrantLock.newCondition()
提供的
Condition
实现对
ReentrantLock
所做的行为相同。当然,此
Condition
只能用于写入锁。
读取锁不支持 Condition
,readLock().newCondition()
会抛出
UnsupportedOperationException
。
此类支持一些确定是保持锁还是争用锁的方法。这些方法设计用于监视系统状态,而不是同步控制。
java实现如下:
package andy.thread.test; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author Zhang,Tianyou * @version 2014年11月9日 上午9:29:42 */ public class ThreadCaChe { private static Map<String, Object> cacheMap = new HashMap<String, Object>(); public static void main(String[] args) { for (int i = 0; i < 10; i++) { new Thread(new Runnable() { @Override public void run() { String obj = (String) getData("andy"); System.out.println(obj); } }).start(); } } public static Object getData(String key) { ReadWriteLock rwlLock = new ReentrantReadWriteLock(); // 先加读锁 rwlLock.readLock().lock(); Object value = null; try { value = cacheMap.get(key); // 若不存在cache中 if (value == null) { // 若果value为空 则释放掉读锁,让该线程获取写锁,而其他线程只能等待该写锁释放,才能在进读锁 rwlLock.readLock().unlock(); // 加写锁 rwlLock.writeLock().lock(); try { if (value == null) { // 从数据中获取数据 value = "andy is shuai ge";// 查询数据库 // 存入缓存中 cacheMap.put(key, value); } } finally { rwlLock.writeLock().unlock(); } rwlLock.readLock().lock(); } } finally { // 释放第一次获取的读锁 rwlLock.readLock().unlock(); } return value; } }
执行效果如下:
andy is shuai ge andy is shuai ge andy is shuai ge andy is shuai ge andy is shuai ge andy is shuai ge andy is shuai ge andy is shuai ge andy is shuai ge andy is shuai ge
多线程之使用读写锁ReentrantReadWriteLock实现缓存系统
标签:多线程 缓存系统 cache reentrantreadwritelo 读写锁
原文地址:http://blog.csdn.net/fengshizty/article/details/40947419