-1

我有这段代码:

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() 立即返回数组,并且数组元素填充在不同的线程中,但是我们得到的结果存储在 AtomicReference 中,直到稍后我们才得到值,所以延迟我添加主函数超过了新线程产生的延迟。我返回的数组是否会填充所有元素?

4

2 回答 2

3

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

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

于 2020-12-18T20:37:39.823 回答
0

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

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

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

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

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

于 2020-12-19T16:50:00.753 回答