如果我们为它分配一个 returns 某个数组的函数,是否会延迟设置 AtomicReference 的值?

Does the value of AtomicReference will be set lazily if we assign a function to it which returns some array?

我有这段代码:

AtomicReference<List<String>> atomicStrings = new AtomicReference<>();
atomicStrings.set(someFunc());
Thread.sleep(10000);
System.out.print(String.join(",", atomicStrings.get()); // will this print a,b,c ?

在哪里

private List<String> someFunc() {
    List<String> list = new ArrayList<>();

    new Thread(() -> {
      try {
        list.add("a");
        Thread.sleep(1000);
        list.add("b");
        Thread.sleep(1000);
        list.add("c");
        Thread.sleep(1000);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }).start();

    return list;
}

当然这是一个非常糟糕的例子,但我试图通过添加延迟来模仿我的真实测试用例。我在这里的问题是,由于 someFunc() returns 数组和数组元素是在不同的线程中填充的,但是我们得到的结果存储在 AtomicReference 中,直到稍后我们才得到值,我在 main 函数中添加的延迟比生成的新线程所花费的延迟要多。我返回的数组会填充所有元素吗?

您不是在向它“分配函数”,您是立即计算 someFunc并将值(对列表的引用)放在AtomicReference.

原子 类 有特殊的 happens-before 约束,所以 someFunc 中的列表发生的任何事情都保证对任何人​​可见从引用中检索列表,但是您在衍生线程中对列表的修改与程序的其余部分没有 happens-before 关系。行为未定义,直到并包括 ConcurrentModificationException.

Does the value of AtomicReference will be set lazily if we assign a function to it which returns some array?

首先,AtomicReference.set() 是直接的,绝不是懒惰的。如果我们查看您的代码,我们会看到 someFunc() returns 和 ArrayList,因此这将立即设置为 atomicStrings。不幸的是,字符串是由另一个线程添加到列表中的,主线程(即 运行 someFunc() 和创建列表)与将字符串添加到列表的线程之间没有同步.任何时候两个不同的线程正在访问同一个对象,尤其是改变那个对象,你需要担心互斥(竞争条件)和内存同步。

您可以用来解决您的特定问题的一件事是使用同步 class 而不是 ArrayListBlockingQueueBlockingQueue 处理所有内存同步和互斥锁定,以确保适当地完成来自多个线程的访问。

BlockingQueue<String> queue = new ArrayBlockingQueue<>();

然后,当内部线程调用 queue.add("a"); 并在 10 秒过期后主线程调用 queue.iterator() 时,它们将看到相同的字符串集合。不需要 AtomicReference 因为原子 class 主线程和内线程将共享 ArrayBlockingQueue .