【问题标题】:Java: Obtaining multiple locksJava:获取多个锁
【发布时间】:2014-07-13 12:10:08
【问题描述】:

在这种情况下如何获得多个锁:

public class DoubleCounter
{
    private int valA = 0;
    private int valB = 0;

    private Object lockA = new Object();
    private Object lockB = new Object();

    public void incrementA()
    {
        synchronized (lockA)
        {
            valA++;
        }
    }

    public void incrementB()
    {
        synchronized (lockB)
        {
            valB++;
        }
    }

    public void print()
    {
        //I have to obtain both lockA & lockB before executing this:
        System.out.format("valA: %d\nvalB: %d", valA, valB);
    }
}

请记住,我不希望一个线程执行 incrementA() 阻止另一个线程执行 incrementB() - 因此我不想使用同步方法。

在 StackOverflow 上曾两次询问过类似(不完全相同)的问题,但我仍然没有得到我想要的答案。我唯一知道的是,我不应该将一个 synchronized() 嵌套在另一个 synchornized() 中。

【问题讨论】:

  • 是的,您应该嵌套同步块。这是唯一的方法。没有任何原语可以让您的线程等待,直到它可以同时获取两个锁然后同时获取它们。强制执行锁定获取顺序以防止死锁。
  • 请确保您不要在某处执行lockA -> lockB -> stuff,然后再执行lockB -> lockA -> stuff,因为您会遇到死锁。顺便说一句,您应该使用新的 Lock API 而不是 Object - 它使事情更加明确。
  • 看看this

标签: java concurrency locking synchronized


【解决方案1】:

考虑一个选项

public void print()
{
    final int localA;
    synchronized(lockA)
    {
        localA = valA;
    }

    final int localB;
    synchronized(lockB)
    {
        localB = valB;
    }

    //I have to obtain both lockA & lockB before executing this:
    System.out.format("valA: %d\nvalB: %d", localA, localB);
}

另一种选择是简单地使用AtomicInteger,这要简单得多。

【讨论】:

  • 这在一定程度上解决了这个特定问题,但是如果我使用的不是整数并且制作共享对象的深层副本会占用大量内存怎么办?
  • 那么你将不得不嵌套你的锁并且/非常/小心嵌套锁/总是/以相同的顺序获得。
  • 不!这意味着状态将不一致。 valB 在你阅读之前可能会发生一些事情,但在阅读 valA 之后。如果 OP 想要打印一致的状态(考虑到问题就是这种情况),这完全没用。
  • @BoristheSpider 远不清楚 OP 是否过度关注不一致的状态(在 2 个明显不协调的对象之间)。明确表达的愿望是避免嵌套同步。然而,从回复中可以看出,提出的问题是根据实际用例人为简化的。
  • 我不同意 - 问题中代码 sn-p 中的注释清楚地表明 OP 希望在打印之前获取两个锁。但是 OP 想要一种同时获取它们而不是顺序获取它们的方法。
猜你喜欢
  • 1970-01-01
  • 2022-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-07
  • 2016-09-27
  • 2016-01-23
  • 2016-12-29
相关资源
最近更新 更多