在Java中重新分配列表是线程安全的吗?

在Java中重新分配列表是线程安全的吗?,java,multithreading,list,Java,Multithreading,List,我在玩ArrayList上的两个线程。我知道您不能在迭代时修改列表,但是Java允许我在循环中重新分配并替换整个列表,没有任何问题。这是线程安全的吗 public class Main { static List<String> list = Arrays.asList("hi", "there", "friend"); public static void main(String... args) throws InterruptedException {

我在玩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");
    }
}
我希望hi之后会出现并发问题,但我在那里遇到了hi


我认为这是可行的,因为Java确实在引用上按值复制,但我担心我的每1分钟重新分配一次数组的生产应用程序有一天可能会崩溃。谢谢大家

您没有看到更新的列表内容,因为增强的for循环在幕后使用了迭代器。因此,您正在使用旧列表的迭代器来迭代数据,即使在赋值完成之后也是如此。这意味着这两个列表都在范围内,而不是垃圾收集。一旦isReassigned为true,如果列表中有迭代器,则可以看到新内容

我对你的代码做了一些修改,添加了一个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 volatile将解决此问题


您看不到更新的列表内容,因为增强的for循环在幕后使用了迭代器。因此,您正在使用旧列表的迭代器来迭代数据,即使在赋值完成之后也是如此。这意味着这两个列表都在范围内,而不是垃圾收集。一旦isReassigned为true,如果列表中有迭代器,则可以看到新内容

我对你的代码做了一些修改,添加了一个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 volatile将解决此问题


让它不稳定,你就会好起来。让它不稳定,你就会好起来。+1变为常规for循环,输出OP期望的结果。但是,在列表标记为volatile或使用某些同步之前,它是不可靠的,因为列表的新引用可能对其他线程不可见。+1更改为常规for循环会输出OP所期望的结果。但是,在列表标记为volatile或使用某些同步之前,它是不可靠的,因为列表的新引用可能对其他线程不可见。