【问题标题】:Locking in Highly Concurrent System锁定高并发系统
【发布时间】:2012-02-23 17:48:31
【问题描述】:

我在一个高度并发的系统中有一堂课。该类的方法getResolvedClassName() 会产生死锁。所以我是这样设计的:

public class ClassUtils {

    private static ClassUtils classUtils;

    private transient Object object = new Object();

    private synchronized Object getObjectLock() {
        return object;
    }

    public void getResolvedClassName(Class<?> clazz) {
        synchronized (getObjectLock()) {
            //some job will be done here
        }       
    }

    public synchronized static ClassUtils getInstance() {
        if(classUtils == null) {
            classUtils = new ClassUtils();
        }
        return classUtils;
    }   
}

我的做法是否正确?任何信息都会对我有所帮助。

谢谢。


编辑:

public class ClassUtils {

    private static final ClassUtils classUtils = new ClassUtils();
    private ReentrantLock lock = new ReentrantLock();

    public void getResolvedClassName(Class<?> clazz) {
        lock.lock();
        //some job will be done here
        lock.unlock();      
    }

    public static ClassUtils getInstance() {        
        return classUtils;
    }   
}

【问题讨论】:

  • 其他人可能不同意,但我认为这个问题有点太模糊,无法提供有用的答案。
  • private transient Object object - 不应该是final吗?
  • 让你的锁final,不是暂时的。删除它的getter(直接在方法中使用属性)。您的单例初始化方法已损坏,请使用双重锁定检查或枚举。有关更复杂的锁类型,请参阅此页面:- docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/…
  • 同意,它应该是最终的,而且因为它是私有的,所以不需要私有 getter。

标签: java concurrency locking deadlock


【解决方案1】:

有几件事很突出:

  1. 我不认为transient 关键字means what you think it means。该关键字与同步无关,仅在序列化类时使用。您可能会将其与volatile 混淆。顺便说一句,这里也不需要volatile

  2. 你的单例的延迟初始化可能是不必要的。你为什么不直接做private static final ClassUtils classUtils = new ClassUtils();?那么你的getInstance()方法就不需要同步了,只需return classUtils;即可,也是线程安全的。您还应该始终将单例实例声明为 final

  3. 不需要getObjectLock() 的整个情况。您可以在this 上进行同步(即将getResolvedClassname 变成synchronized 方法),这样会更安全、更干净。

您还可以调查java.util.concurrent.Lock 类,看看是否有比在Object 上同步更合适的方法,Object 现在被认为是糟糕的形式。

【讨论】:

  • 非常感谢。我已经编辑了我的问题并添加了一个代码 sn-p。现在可以了吗?
  • @TapasBose 是,但我不会使用ReentrantLock。使用private final Object lock = new Object() 并在其上进行同步更简单。如果您坚持使用ReentrantLock,我建议两件事:将字段设为final,并将getResolvedClassName 中的代码放入try-finally 语句中。 lock.lock() 应该是 try 块中的第一个语句,lock.unlock() 应该放在 finally 块中。这样做是为了确保在发生异常时锁会被解锁。
【解决方案2】:

这个问题确实有点模糊,我看不出使用单例的目的以及为什么需要同步才能完成某些工作。如果它不访问可变状态,则不需要同步。我只能说三个锁(ClassUtils.classClassUtils 实例和object)几乎肯定会增加不必要的复杂性。此外,正如 Justin 所说,您应该将 object 设为 final,然后您就不需要同步来访问它。

【讨论】:

    【解决方案3】:

    你的问题有点一般。但是,您可以考虑将该值初始化为不可变的。许多不可变的初始化值是线程安全的,不需要锁定。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-20
      • 1970-01-01
      • 2015-01-17
      • 1970-01-01
      • 1970-01-01
      • 2014-04-08
      • 2011-11-04
      相关资源
      最近更新 更多