同步整数值 [英] Synchronizing on an Integer value

查看:115
本文介绍了同步整数值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


可能重复:

增加java中锁定数量的最佳方法是什么?

Possible Duplicate:
What is the best way to increase number of locks in java

假设我想根据整数id值进行锁定。在这种情况下,有一个函数可以从缓存中提取一个值,并且如果值不存在则执行相当昂贵的检索/存储到缓存中。

Suppose I want to lock based on an integer id value. In this case, there's a function that pulls a value from a cache and does a fairly expensive retrieve/store into the cache if the value isn't there.

现有的代码未同步,可能触发多个检索/存储操作:

The existing code isn't synchronized and could potentially trigger multiple retrieve/store operations:

//psuedocode
public Page getPage (Integer id){
   Page p = cache.get(id);
   if (p==null)
   {
      p=getFromDataBase(id);
      cache.store(p);
   }
}

我想做的是同步检索关于id,例如

What I'd like to do is synchronize the retrieve on the id, e.g.

   if (p==null)
   {
       synchronized (id)
       {
        ..retrieve, store
       }
   }

不幸的是这赢了因为2个单独的调用可以具有相同的Integer id值但是具有不同的Integer对象,所以它们不会共享锁,并且不会发生同步。

Unfortunately this won't work because 2 separate calls can have the same Integer id value but a different Integer object, so they won't share the lock, and no synchronization will happen.

是否有一种简单的方法可以确保您拥有相同的Integer实例?例如,这是否有效:

Is there a simple way of insuring that you have the same Integer instance? For example, will this work:

 syncrhonized (Integer.valueOf(id.intValue())){

Integer.valueOf()的javadoc似乎意味着你可能会获得相同的实例,但那并不是'看起来像一个保证:

The javadoc for Integer.valueOf() seems to imply that you're likely to get the same instance, but that doesn't look like a guarantee:


返回表示指定int值的Integer实例

如果一个新的Integer实例不需要
,这个方法通常应优先使用
而不是
构造函数Integer(int),因为这个
方法很可能通过经常缓存
请求值来产生
显着更好的空间和时间
性能。

Returns a Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values.

所以,关于如何获得保证相同的Integer实例的任何建议,除了更精细的解决方案,比如保持Lock对象的WeakHashMap键入int? (没错,看起来似乎必须有一个明显的单行而不是我错过了。)

So, any suggestions on how to get an Integer instance that's guaranteed to be the same, other than the more elaborate solutions like keeping a WeakHashMap of Lock objects keyed to the int? (nothing wrong with that, it just seems like there must be an obvious one-liner than I'm missing).

推荐答案

您真的不想在 Integer 上进行同步,因为您无法控制哪些实例相同以及哪些实例不同。 Java只是不提供这样的工具(除非你在小范围内使用整数),它们可以在不同的JVM中可靠。如果你真的必须在整数上进行同步,那么你需要保留一个Map或整数集,以便保证你得到你想要的确切实例。

You really don't want to synchronize on an Integer, since you don't have control over what instances are the same and what instances are different. Java just doesn't provide such a facility (unless you're using Integers in a small range) that is dependable across different JVMs. If you really must synchronize on an Integer, then you need to keep a Map or Set of Integer so you can guarantee that you're getting the exact instance you want.

更好的方法是创建一个新对象,可能存储在由 Integer 键入的 HashMap 中,以便同步。这样的事情:

Better would be to create a new object, perhaps stored in a HashMap that is keyed by the Integer, to synchronize on. Something like this:

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 。你可以这样做:

To explain this code, it uses ConcurrentMap, which allows use of putIfAbsent. You could do this:

  locks.putIfAbsent(id, new Object());

但是你会因为每次访问而产生(小)成本。为避免这种情况,我只将整数本身保存在 Map 中。这实现了什么?为什么这与使用Integer本身有什么不同呢?

but then you incur the (small) cost of creating an Object for each access. To avoid that, I just save the Integer itself in the Map. What does this achieve? Why is this any different from just using the Integer itself?

当你从一个 get()时code> Map ,将密钥与 equals()进行比较(或者至少使用的方法相当于使用等于())。具有相同值的两个不同的Integer实例将彼此相等。因此,您可以将 new Integer(5)的任意数量的不同Integer实例作为参数传递给 getCacheSyncObject 并且您将始终只返回传递的包含该值的第一个实例。

When you do a get() from a Map, the keys are compared with equals() (or at least the method used is the equivalent of using equals()). Two different Integer instances of the same value will be equal to each other. Thus, you can pass any number of different Integer instances of "new Integer(5)" as the parameter to getCacheSyncObject and you will always get back only the very first instance that was passed in that contained that value.

您可能不希望在<$ c $上同步的原因c> Integer ...如果多个线程在 Integer 对象上同步,你可能会陷入死锁,因此他们无意中在需要时使用相同的锁使用不同的锁。你可以使用

There are reasons why you may not want to synchronize on Integer ... you can get into deadlocks if multiple threads are synchronizing on Integer objects and are thus unwittingly using the same locks when they want to use different locks. You can fix this risk by using the

  locks.putIfAbsent(id, new Object());

版本因此每次访问缓存都会产生(非常)小的成本。这样做,您可以保证此类将在其他类不同步的对象上进行同步。总是好事。

version and thus incurring a (very) small cost to each access to the cache. Doing this, you guarantee that this class will be doing its synchronization on an object that no other class will be synchronizing on. Always a Good Thing.

这篇关于同步整数值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆