你能用Java锁定本地对象吗?

时间:2009-10-16 19:19:51

标签: java concurrency

我有这段代码

private Templates retrieveFromCache(String name) {
        TemplatesWrapper t = xlCache.get(name);
        synchronized(t){
            if (!t.isValid()) {
                xlCache.remove(name);
                return null;
            }
        }
        return t.getTemplate();
    }

xlCacheConcurrentHashMap;我在t上进行同步的原因是2个线程可以交错,当线程1验证谓词时,线程2已经从地图中删除了对象,然后抛出了NullPointerException我的假设是正确的,因为我知道并发性是推理的难度之一。然后到我原来的问题,我可以锁定t,即使它是本地的吗?

这也是private方法,它从public方法调用,是否会产生差异?

编辑:由于NullPointerException返回remove()使同步失去意义,因此抛出boolean的原始前提不正确;但是,我的问题是锁定了一个本地对象。

5 个答案:

答案 0 :(得分:2)

如果指定的密钥不存在,

ConcurrentHashMap(和Map / ConcurrentMap一般)不会抛出异常。这就是remove方法返回boolean的原因,以指示是否实际删除了

但是,你可以锁定局部变量。毕竟,您实际上是通过引用(以及与引用对象关联的监视器)锁定的,而不是变量 - 而另一个并发运行的方法将具有相同的引用。

答案 1 :(得分:2)

您可以锁定所需的任何对象。但是,在您的情况下,看起来您可以更清晰,更安全地解决它。

同步应尽可能本地化。由于您从某个未知位置获取TemplatesWrapper,因此任何人都可以在其上进行同步,这使得很难控制并发性。通过查看代码被锁定的原因,它也应该尽可能明显。

最好将同步放在xlCache中,例如removeIfInvalid()

答案 2 :(得分:1)

是的,这样可以正常工作。

您可以在java中的任何对象上进行同步,这样您的代码就可以运行并且是线程安全的。

因为你没有检查是否为空,所以公寓。我猜你刚刚错过了你的代码示例?

答案 3 :(得分:1)

更好的方法是使用ConcurrentMap中的2 arg remove方法(假设t具有合理的equals实现)。那么你不需要任何同步:

private Templates retrieveFromCache(String name) {
    TemplatesWrapper t = xlCache.get(name);

    if (!t.isValid()) {
        xlCache.remove(name, t);
        return null;
    }
    return t.getTemplate();
}

答案 4 :(得分:0)

如果remove(null)会调用空指针异常,这似乎是合理的。如果你不认为碰撞是一个常见的问题,你也可以实现一个可能更快的代码版本,只需将try / catch包裹起来而不是同步。

在任何一种情况下,我都会在那里添加评论来解释你为什么做了你所做的事情,所以从现在开始一个月,它仍然有意义。