在Java中正确同步equals() [英] Correctly synchronizing equals() in Java

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

问题描述

我有以下类只包含一个字段 i 。对象的锁定(this)保护对该字段的访问。当实现equals()时,我需要锁定这个实例(a)和另一个(b)。如果线程1调用a.equals(b)并且同时线程2调用b.equals(a),则锁定顺序在两个实现中是相反的,并且可能导致死锁。

I have the following class which contains only one field i. Access to this field is guarded by the lock of the object ("this"). When implementing equals() I need to lock this instance (a) and the other (b). If thread 1 calls a.equals(b) and at the same time thread 2 calls b.equals(a), the locking order is reverse in the two implementations and may result in deadlock.

我应该如何为具有同步字段的类实现equals()?

How should I implement equals() for a class which has synchronized fields?

public class Sync {
    // @GuardedBy("this")
    private int i = 0;
    public synchronized int getI() {return i;}
    public synchronized void setI(int i) {this.i = i;}

    public int hashCode() {
        final int prime = 31;
        int result = 1;
        synchronized (this) {
            result = prime * result + i;
        }
        return result;
    }

    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Sync other = (Sync) obj;
        synchronized (this) {
            synchronized (other) {
                // May deadlock if "other" calls 
                // equals() on "this" at the same 
                // time 
                if (i != other.i)
                    return false;
            }
        }
        return true;
    }
}


推荐答案

尝试在对象内部同步等于 hashCode 将无法正常工作。考虑一个 HashMap 的情况,它使用 hashCode 来发现一个对象将在哪个桶,然后使用等于以顺序搜索存储桶中的所有对象。

Trying to synchronize equals and hashCode inside the object will not work properly. Consider the case of a HashMap that uses hashCode to discover which "bucket" an object will be in, and then uses equals to sequentially search all objects in the bucket.

如果允许对象以改变方式的方式进行变异 hashCode 等于的结果你最终会得到 HashMap 调用 hashCode 。它获取锁,获取哈希并再次释放锁。 HashMap 然后继续计算要使用的桶。但在之前,HashMap 可以获得等于其他人的锁定并获取锁定并改变对象,以便等于变得不一致 hashCode 的先前值。这将导致灾难性的结果。

If objects are allowed to mutate in a way that changes the outcomes of hashCode or equals you could end up with a scenario where HashMap calls hashCode. It acquires the lock, gets the hash and releases the lock again. HashMap then proceeds to compute which "bucket" to use. But before HashMap can acquire the lock on equals someone else grabs the lock and mutates the object so that equals become inconsistent with the previous value of hashCode. This will lead to catastrophic results.

hashCode 和equals方法在很多地方使用并且是核心到Java集合API。重新考虑不需要同步访问这些方法的应用程序结构,我可能很有价值。或者至少不同步对象本身。

The hashCode and equals methods are used in a lot of places and is core to the Java collections API. I might be valuable to rethink your application structure that do not require synchronized access to these methods. Or at the very least not synchronize on the object itself.

这篇关于在Java中正确同步equals()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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