如果我们为它分配一个 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 而不是 ArrayList
的 BlockingQueue
。 BlockingQueue
处理所有内存同步和互斥锁定,以确保适当地完成来自多个线程的访问。
BlockingQueue<String> queue = new ArrayBlockingQueue<>();
然后,当内部线程调用 queue.add("a");
并在 10 秒过期后主线程调用 queue.iterator()
时,它们将看到相同的字符串集合。不需要 AtomicReference
因为原子 class 主线程和内线程将共享 ArrayBlockingQueue
.
我有这段代码:
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 而不是 ArrayList
的 BlockingQueue
。 BlockingQueue
处理所有内存同步和互斥锁定,以确保适当地完成来自多个线程的访问。
BlockingQueue<String> queue = new ArrayBlockingQueue<>();
然后,当内部线程调用 queue.add("a");
并在 10 秒过期后主线程调用 queue.iterator()
时,它们将看到相同的字符串集合。不需要 AtomicReference
因为原子 class 主线程和内线程将共享 ArrayBlockingQueue
.