【问题标题】:Synchronizing on two or more objects (Java)在两个或多个对象上同步 (Java)
【发布时间】:2009-11-27 11:10:55
【问题描述】:

我有类似下面的代码:

public class Cache{
 private final Object lock = new Object();
 private HashMap<Integer, TreeMap<Long, Integer>> cache = 
  new HashMap<Integer, TreeMap<Long, Integer>>();
 private AtomicLong FREESPACE = new AtomicLong(102400);

 private void putInCache(TreeMap<Long, Integer> tempMap, int fileNr){
  int length; //holds the length of data in tempMap
  synchronized(lock){
   if(checkFreeSpace(length)){
    cache.get(fileNr).putAll(tmpMap);
    FREESPACE.getAndAdd(-length);
   }
  }
 }

 private boolean checkFreeSpace(int length){      
  while(FREESPACE.get() < length && thereIsSomethingToDelete()){
   // deleteSomething returns the length of deleted data or 0 if 
   // it could not delete anything
   FREESPACE.getAndAdd(deleteSomething(length));
  }
  if(FREESPACE.get() < length) return true;
  return false;
 }
}

putInCache 每秒被大约 139 个线程调用。我可以确定这两种方法会在cacheFREESPACE 上同步吗?另外,checkFreeSpace() 是多线程安全的,即我可以确定一次只会调用一次此方法吗?这段代码的“多线程安全”可以改进吗?

【问题讨论】:

  • (在该代码中使用 AtomicLong 毫无意义。)

标签: java object synchronized multithreading


【解决方案1】:

要完全回答您的问题,您需要展示 thereIsSomethingToDelete() 和 deleteSomething() 方法的实现。

鉴于 checkFreeSpace 是一个公共方法(它真的需要吗?)并且是不同步的,它可能会在 putInCache() 方法中的同步块运行时被另一个线程调用。这本身可能不会破坏任何东西,因为 checkFreeSpace 方法似乎只能增加可用空间量,而不能减少它。

如果 thereIsSomethingToDelete() 和 deleteSomething() 方法没有正确同步它们对缓存对象的访问,使用相同的对象锁,会更严重(并且代码示例不允许我们确定这一点)由 putInCache() 使用。

【讨论】:

  • 感谢您的回复。首先,public 不是什么大问题,因为这两个方法只被同一个类中的另一个方法调用。至于thereIsSomethingToDelete()deleteSomething(),其实我没有这些方法。他们的逻辑包含在checkFreeSpace 方法中,但是如果我将所有代码都放在这里,那就太乱了。所以让我们假设这些方法是正确同步的。
  • 对不起,我选择了错误的方法来提问。请查看编辑后的版本。
  • 所以大概 putInCache() 也不是真正的私有(否则如何实际使用该类)。我认为该类是如上所述的线程安全的,因为只有当线程持有由 putInCache() 同步块建立的锁时,才能发生对可变状态的所有访问。
【解决方案2】:

您通常不会在要直接控制访问的字段上进行同步。 您要同步访问的字段必须只能从同步块(在同一对象上)中访问,才能被视为线程安全。您已经在putInCache() 中执行此操作。 因此,因为checkFreeSpace() 以非同步方式访问共享状态,所以它不是线程安全的。

【讨论】:

  • 如果我将putInCache() 声明为synchronized 会怎样?这会让这两种方法“更安全”吗?
  • @Azimuth 您需要在字段级别保护访问,这意味着访问这些字段的所有方法都需要在同一个锁对象上同步。简而言之,您还需要在 checkFreeSpace() 中添加一个同步块。
猜你喜欢
  • 1970-01-01
  • 2022-01-16
  • 2010-09-19
  • 1970-01-01
  • 2014-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多