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

qgzx9mmu  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(271)

我有一段代码:

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()立即返回数组,数组元素被填充到另一个线程中,但是我们得到的结果存储在一个原子引用中,直到稍后才得到值,因此我在main函数中添加的延迟比生成新线程所需的延迟要大。我返回的数组是否会被填充所有元素?

nwnhqdif

nwnhqdif1#

如果我们给atomicreference分配一个返回数组的函数,它的值是否会延迟设置?
首先, AtomicReference.set() 是直接的,决不懒惰。如果我们看一下你的代码,就会发现 someFunc() 返回一个 ArrayList 所以这将立即被设置为 atomicStrings . 不幸的是,字符串是由另一个线程添加到列表中的,并且正在运行的主线程之间没有同步 someFunc() 创建列表,以及向列表中添加字符串的线程。每当两个不同的线程访问同一个对象时,尤其是对该对象进行变异时,您需要担心互斥锁(竞争条件)和内存同步。
有一件事你可以用来解决你的具体问题是使用 BlockingQueue 它是一个同步类而不是 ArrayList . BlockingQueue 注意所有的内存同步和互斥锁,以确保从多个线程进行的访问是正确的。

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

然后,当内部线程调用 queue.add("a"); 10秒后,主线程调用 queue.iterator() ,它们将看到相同的字符串集合。没有必要这样做 AtomicReference 因为主线程和内线程将共享的原子类是 ArrayBlockingQueue .

9w11ddsr

9w11ddsr2#

你不是在给它“分配一个函数”,而是在立即计算 someFunc 并将值(对列表的引用)放置在 AtomicReference .
原子类有特殊的happens before约束,因此 someFunc 保证对从引用中检索列表的任何人都可见,但是您在派生线程中对列表的修改与程序的其余部分没有“发生在”关系。行为未定义,包括 ConcurrentModificationException .

相关问题