可能重复:
增加java中锁的数量的最佳方法是什么
假设我想基于整数id值进行锁定.在这种情况下,有一个函数可以从缓存中提取值,并且如果值不存在则执行相当昂贵的检索/存储到缓存中.
现有代码未同步,可能会触发多个检索/存储操作:
//psuedocode
public Page getPage (Integer id){
Page p = cache.get(id);
if (p==null)
{
p=getFromDataBase(id);
cache.store(p);
}
}
Run Code Online (Sandbox Code Playgroud)
我想要做的是同步id上的检索,例如
if (p==null)
{
synchronized (id)
{
..retrieve, store
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,这不起作用,因为2个单独的调用可以具有相同的Integer id值但是具有不同的Integer对象,因此它们不会共享锁,并且不会发生同步.
有没有一种简单的方法可以确保您拥有相同的Integer实例?例如,这会工作:
syncrhonized (Integer.valueOf(id.intValue())){
Run Code Online (Sandbox Code Playgroud)
Integer.valueOf()的javadoc似乎意味着您可能会获得相同的实例,但这看起来不像是一个保证:
返回表示指定int值的Integer实例.如果不需要新的Integer实例,通常应优先使用此方法,而不是构造函数Integer(int),因为此方法可能通过缓存频繁请求的值来显着提高空间和时间性能.
那么,关于如何获得保证相同的Integer实例的任何建议,除了更精细的解决方案,比如保持Lock对象的WeakHashMap键入int?(没错,看起来似乎必须有一个明显的单行而不是我错过了).
现在没有在java 8的Javadoc推出了一个新的API computeIfAbsent 它的ConcurrentHashMap的impelementation状态:
如果指定的键尚未与值关联,则尝试使用给定的映射函数计算其值,并将其输入此映射,除非为null.整个方法调用是以原子方式执行的,因此每个键最多应用一次该函数.其他线程在此映射上的某些尝试更新操作可能在计算进行时被阻止,因此计算应该简短,并且不得尝试更新此映射的任何其他映射.
那么,在密钥已经存在且计算不需要的情况下,它对锁定此实现有什么看法呢?即使不需要计算,只是映射函数调用是同步的,以防止调用函数两次,整个方法computeIfAbsent是否如文档中所述同步?
请考虑以下方法:
public void upsert(int customerId, int somethingElse) {
// some code which is prone to race conditions
}
Run Code Online (Sandbox Code Playgroud)
我想保护此方法不受竞争条件的影响,但只有当两个具有相同线程的线程同时customerId调用它时才会发生这种情况.如果我制作整个方法,synchronized它会降低效率而且并不是真正需要的.我真正想要的是围绕它同步它customerId.这有可能以某种方式与Java?是否有任何内置工具或者我需要Map的Integers是锁使用?
如果您认为我在这里做错了,请随时咨询:)
谢谢!