首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ReentrantReadWriteLock锁升级方法

ReentrantReadWriteLock锁升级方法
EN

Code Review用户
提问于 2012-06-20 16:31:54
回答 2查看 4.4K关注 0票数 2

我有一个关于锁upgrading.Specifically的问题,困扰我的是readlock.unlock()和writelock.lock().我正在为一个示例缓存提供一个几乎完全的实现,我只是省略了从数据库中实际加载缓存的数据。

我很感谢你能回顾一下代码并分享你的想法。我试图在java注释中表达我的关切。我的问题是如何正确同步以避免重新检查加载缓存中的缓存。

代码语言:javascript
复制
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;




public class JavaRanchSampleCache {

    private ConcurrentHashMap<String, ReentrantReadWriteLock> refreshLocks = new ConcurrentHashMap<String, ReentrantReadWriteLock>();
    private ConcurrentHashMap<String, HashMap<String, String>> cacheData = new ConcurrentHashMap<String, HashMap<String, String>> ();

    public  HashMap<String, String> getCachedData(String cacheKey)
    {
        ReentrantReadWriteLock lock = refreshLocks.get(cacheKey);

        if(lock==null)
        {
            lock=new ReentrantReadWriteLock();      
            ReentrantReadWriteLock previous=refreshLocks.putIfAbsent(cacheKey, lock);
            if(previous!=null)//null means no previous lock object,first time usage
                lock=previous;      
        }

        //we have a safe lock at this point
        try
        {
            lock.readLock().lock();//read the cached item for correspoding cacheKey
            HashMap<String, String> cachedItem=cacheData.get(cacheKey);
            if(cachedItem==null)//it is not cached yet.Load to cache on first request
            {
                cachedItem=loadItemExpensive(cacheKey);
            }

            return cachedItem;//return the cached item.

        }
        finally
        {
            lock.readLock().unlock();   
        }

    }

    private HashMap<String, String> loadItemExpensive(String cahceKey)
    {
        ReentrantReadWriteLock lock = this.refreshLocks.get(cahceKey);
        HashMap<String, String> cachedItem=null;
        try
        {
             /*these two lines are for lock upgrading
             * BUT what happens if another thread interacts between line1 and line2
             * I mean after the readlock is relased,some OTHER thread might gain the writelock
             * before this thread and perform loaddata and update cache operation.
             * So should I check the cache once more to see if some other thread 
             * has updated the cache? I 'feel' that I should,but it is ugly,i need some clever way.
             */
            lock.readLock().unlock();//line1
            lock.writeLock().lock();//line2


            /*omitted load data from some expensive store such as database or remote server*/

            return  cachedItem;
        }
        finally
        {
            lock.readLock().lock();//writelock owner can grant readlock immediately.
            lock.writeLock().unlock();//lock released
        }
    }

}
EN

回答 2

Code Review用户

回答已采纳

发布于 2012-06-20 17:33:44

你的恐惧是有道理的。一旦你松开锁,所有的赌注都取消了。当您获得写锁时,您将需要检查另一个线程是否改变了缓存。不要认为它是“丑陋的”,认为它是“正确的”。继续使用注释来解释你在做什么,以及为什么你要这么做。

简而言之,读/写锁不能同时支持升级和降级。必须始终以相同的顺序获得多个锁(在这种情况下,写然后读取),否则就会发生致命的拥抱。因此,当选择另一种方式时(读然后写),您必须释放锁,此时必须重新考虑基于当前状态所做的任何决定。

但是还有其他的选择,取决于你的具体情况。

一种是总是获得一个写锁,以便在数据已经存在的情况下进行修改,并将其降级为读锁。这可能不是您想要的,特别是在大多数操作都是只读的情况下,因为它会导致锁定争用和负载下的不良响应时间。

其他选项可能包括允许多个线程(冗余地)执行昂贵的负载,以及在插入表时获取写锁。或者只是盲目地覆盖现有条目(在最后一种情况下,您真正需要的是ConcurrentHashMap)。这完全取决于你愿意容忍什么情况。

希望这能有所帮助。

票数 4
EN

Code Review用户

发布于 2013-09-13 12:01:27

这是一个老问题,但这里有一个问题的解决方案,以及一些背景信息。

如果您需要在不首先释放读锁的情况下安全地获取写锁,请查看另一种类型的锁,即读-写-__update锁。

我编写了一个ReentrantReadWrite_Update_Lock,并在Apache2.0许可这里下作为开放源码发布了它。我还向JSR166 并发-利息邮件列表发布了有关该方法的详细信息,该方法通过了名单上成员的反复审查。

这个方法非常简单,而且正如我在并发感兴趣方面所提到的,这个想法并不是完全新的,因为Linux内核邮件列表至少早在2000年就已经讨论过了。此外,.Net平台的ReaderWriterLockSlim也支持锁升级。因此,这个概念到目前为止还没有在Java (AFAICT)上实现。

其想法是除了读锁和写锁之外,还提供更新锁。更新锁是读锁和写锁之间的一种中间类型的锁。与写锁一样,一次只能有一个线程获得更新锁。但就像读锁一样,它允许对持有它的线程进行读取访问,并并发访问持有常规读锁的其他线程。关键的特性是,更新锁可以从只读状态升级到写锁,这不会受到死锁的影响,因为只有一个线程可以保存更新锁,并且一次可以升级。

这支持锁升级,而且它比传统的读写器锁在具有读写访问模式的应用程序中更有效,因为它阻塞读取线程的时间更短。

站点上提供了示例用法。该库具有100%的测试覆盖率,并且位于Maven中心。

注意,有一个类似的问题,这里

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/12939

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档