你真的不想在上同步
Integer,因为你无法控制哪些实例相同,哪些实例不同。Java只是没有提供跨不同JVM可靠的功能(除非你在较小范围内使用
Integers)。如果确实必须在Integer上进行同步,则需要保留Map或Integer Set,以便可以保证获得所需的确切实例。
最好是创建一个新对象,也许将其存储在以
HashMap键为键的对象中以
Integer进行同步。像这样:
public Page getPage(Integer id) { Page p = cache.get(id); if (p == null) { synchronized (getCacheSyncObject(id)) { p = getFromDatabase(id); cache.store(p); } }}private ConcurrentMap<Integer, Integer> locks = new ConcurrentHashMap<Integer, Integer>();private Object getCacheSyncObject(final Integer id) { locks.putIfAbsent(id, id); return locks.get(id);}为了解释该代码,它使用
ConcurrentMap,允许使用
putIfAbsent。你可以这样做:
locks.putIfAbsent(id, new Object());
但随后你需要为每次访问创建一个对象,而这笔费用很小。为避免这种情况,我只将Integer本身保存在中Map。这能达到什么目的?为什么这与仅使用Integer本身有什么不同?
当你
get()从中执行a时
Map,会将键与进行比较
equals()(或至少使用的方法等效于使用
equals())。具有相同值的两个不同的Integer实例将彼此相等。因此,你可以将“ new Integer(5)”的任意数量的不同Integer实例作为参数传递给getCacheSyncObject你,并且你将始终始终只获取在包含该值的那个实例中传递的第一个实例。
有一些原因可能导致你不希望在
Integer...上进行同步…如果多个线程在
Integer对象上进行同步,从而在它们想要使用不同的锁时不经意地使用相同的锁,则可能会陷入死锁。你可以使用
locks.putIfAbsent(id, new Object());
版本,因此每次访问缓存都会产生(非常小的)成本。这样做,你可以确保此类将在没有其他类进行同步的对象上进行同步。永远是一件好事。



