正确的方法来对AtomicReference持有的对象进行相等和哈希码处理 [英] The right way to do equals and hashcode of objects held by AtomicReference

查看:194
本文介绍了正确的方法来对AtomicReference持有的对象进行相等和哈希码处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

AtomicReference 不适用于 Objects.equals() Objects.hash().

    AtomicReference<String> ref1 = new AtomicReference<>("hi");
    AtomicReference<String> ref2 = new AtomicReference<>("hi");
    System.out.println(Objects.equals(ref1, ref2)); //false
    System.out.println(Objects.equals(ref1.get(), ref2.get())); //true but potentially not thread safe
    System.out.println(Objects.hash(ref1) == Objects.hash(ref2)); //false
    System.out.println(Objects.hash(ref1.get()) == Objects.hash(ref2.get())); //true but potentially not thread safe

检查 AtomicReference 持有的两个对象是否相等并以可行且线程安全的方式计算相同哈希的最佳方法是什么?

What's the best way to check if two objects held by AtomicReference are equal and calculate the same hash in a way that both works and is thread safe?

推荐答案

首先,我想对以下语句提出疑问:

First of all, I would like to take issue with this statement:

AtomicReference 不适用于 Objects.equals() Objects.hash().

实际上, AtomicReference (AR)确实在至少两种意义上起作用:

In fact, AtomicReference (AR) does work in at least two senses:

  1. AR符合隐含规范. javadocs 显示 equals hashCode 方法不会被覆盖,因此,这些方法的语义是由 Object 定义的.因此,AR对象对于等于具有身份"语义;也就是说,只有当两个AR对象是同一对象时,它们才是相等的".

  1. AR conforms to the implied specification. The javadocs show that the equals and hashCode methods are not overridden, and that the methods' semantics are therefore defined by Object. Thus, AR objects have "identity" semantics for equals; i.e. two AR objects are "equal" if and only if they are the same object.

AR的行为与标准类库定义的其他可变类型一致:数组, StringBuilder ,其他 Atomic * 类型等等.

AR's behavior is consistent with other mutable types defined by the standard class library: arrays, StringBuilder, other Atomic* types and so on.

我将向您保证,AR的行为可能对您尝试执行的操作没有帮助.但是您会发现 Objects.equals() Objects.hash()与我提到的其他可变类型都存在相同的问题.

I will grant you that AR's behavior may not be helpful to what you are trying to do. But you would find that Objects.equals() and Objects.hash() have the same problems with the other mutable types that I mentioned.

比较一对原子引用的包装值的正确方法是:

The correct way to compare the wrapped values of a pair of atomic references is:

  Objects.equals(ref1.get(), ref2.get());

您(正确地)声明这不是线程安全的,但是(我认为)对于原子类型是期望的.通常,两个原子操作的序列是非原子的.通常,要执行两个操作作为一个原子整体,您需要执行某种形式的锁定.

You state (correctly) that this is not thread-safe, but this is (to my mind) expected for atomic types. As a general rule, a sequence of two atomic operations is non-atomic. As a general rule, to perform two operations as an atomic whole, you need to do some form of locking.

因此,一种简单(但有缺陷)的方法是做到这一点:

So a simple (but flawed) approach is to do this:

  synchronized (ar1) {
      synchronized (ar2) {
           result = ar1.get() == ar2.get();
      }
  }

缺陷是存在死锁的风险...如果两个线程同时交换 ar1 ar2 来同时执行上述代码,则存在死锁的风险.

The flaw is that there is a risk of deadlock ... if two threads execute the above code simultaneously with the ar1 and ar2 interchanged.

该漏洞的一个(假设的)修复方法是确保线程以相同的顺序锁定 ar1 ar2 .您可以(几乎总是)通过使用 ar1.hashCode() ar2.hashCode()来实现一致的顺序;例如

A (hypothetical) fix for the flaw is to ensure that the threads lock ar1 and ar2 in the same order. You can (almost always) achieve that by using ar1.hashCode() and ar2.hashCode() to give you a consistent order; e.g.

  int h1 = ar1.hashCode();
  int h2 = ar2.hashCode();
  if (h1 < h2) {
      synchronized (ar1) {
          synchronized (ar2) {
               result = ar1.get() == ar2.get();
      }
  } else if (h1 > h2) {
      synchronized (ar2) {
          synchronized (ar1) {
               result = ar1.get() == ar2.get();
      }
  } else if (ar1 == ar2) {
      result = true;
  } else {
      // h1 == h2, but ar1 != ar2
  }

但是如您所见,在极少数情况下,hashCode排序不起作用.

But as you can see, in a tiny percentage of cases, hashCode ordering won't work.

我不知道是否有 该子案例的解决方案...使用互斥锁.

And I don't know if there is a solution for that subcase ... using mutex locking.

对此的另一种方法是指出,期望您可以执行此操作实际上是不合理的.这是东西.即使您能够测试两个 AtomicReference 对象确实引用了同一对象,该结果也仅在特定的时间有效.测试完成后的瞬间,某些线程可能会更改其中一个AR,从而使结果无效.

The other approach to this is to point out that it is actually unreasonable to expect that you can do this. Here's the thing. Even if you were able to test that two AtomicReference objects did refer to the same object, that result is only valid for a specific instant in time. The instant after the test completes, the result could be invalidated by some thread changing one of the ARs.

最重要的是,该测试无用,因为它不会告诉您应用程序可以依赖的任何内容.因此(IMO)实施它毫无意义,而担心种族状况则显得毫无意义.

The bottom line is that the test is not useful in that it doesn't tell you anything that your application can rely on. So (IMO) there is little point in implementing it, and even less point in worrying about race conditions.

实用的替代方案是对没有潜在死锁问题的 Lock 或互斥对象使用外部锁定.

The practical alternative is to use external locking on Lock or mutex objects that don't have the problem of potential deadlocks.

这篇关于正确的方法来对AtomicReference持有的对象进行相等和哈希码处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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