java - 在 Java 中重新分配列表是否是线程安全的?
问题描述
我正在使用在 ArrayList 上运行的两个线程。我知道您不能在迭代时修改列表,但 Java 让我在循环中重新分配(替换)整个列表,没有问题。这是线程安全的吗?
public class Main {
static List<String> list = Arrays.asList("hi", "there", "friend");
public static void main(String... args) throws InterruptedException {
boolean isReassigned = false;
for (String s: list) {
System.out.println(s);
if (!isReassigned) {
new Thread(() -> reassignList()).start();
isReassigned = true;
}
Thread.sleep(1000);
}
}
public static void reassignList() {
System.out.println("Reassigning list....");
list = Arrays.asList("goodbye", "old", "list");
}
}
我预计在“嗨”之后会出现并发问题,但我得到了“嗨,朋友”。
我认为这是可行的,因为 Java 确实在引用上按值复制,但我担心我的生产应用程序每 1 分钟重新分配一次数组可能有一天会爆炸。感谢大家!
解决方案
您看不到更新的列表内容,因为增强的 for循环在幕后使用了迭代器。因此,您正在使用迭代器(到旧列表)来迭代数据(即使在分配完成之后)。这意味着这两个列表都在范围内(而不是垃圾收集)。一次,isReassigned
是的,如果你得到一个迭代器,list
你就可以看到新的内容。
我已经稍微更改了您的代码(添加了一个else块)以理解这一点
for (String s: list) {
System.out.println(s);
if (!isReassigned) {
new Thread(() -> reassignList()).start();
isReassigned = true;
} else {
System.out.println("Latest data " + list);
}
Thread.sleep(1000);
}
这产生
hi
Reassigning list....
there
Latest data [goodbye, old, list]
friend
Latest data [goodbye, old, list]
其他几点:
您不应该
isReassigned
从主线程进行设置。必须在分配列表后设置。正如@Kartik 在评论中指出的那样,可能存在可见性问题,其他线程可能看不到所做的更改。标记列表
isReassigned
和易失性将解决这个问题。
推荐阅读
- java - 由于线程池,在可访问性服务中获得大量 ANR
- python - 如果两列中的连续值相同,如何在python中删除重复项?
- rust - 如何强制 rust 正确格式化十六进制和其他非 base-10 整数?
- sql-server-2014 - SQL 代理导出作业因访问被拒绝错误而失败
- unity3d - Hw冻结滚动条中的按钮
- python - Python Anaconda 创建环境(代理集):无效的 IPv6 URL
- unity3d - 在真实世界坐标上生成对象(Mapbox + Unity)
- reactjs - 条件赋值给 const 变量
- typo3 - TYPO3 queryBuilder,如何让 PhpStorm 识别方法?
- c++ - 下标运算符优先级