在Java中重新分配列表是否安全?

时间:2019-02-12 04:24:41

标签: 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 {

        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 there friends”。

我认为这是可行的,因为Java会对引用进行按值复制,但是我担心每隔1分钟重新分配阵列的生产应用可能有一天会崩溃。谢谢大家!

1 个答案:

答案 0 :(得分:4)

您没有看到更新的列表内容,因为增强的 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]

其他几点:

  1. 您不应该在主线程中设置isReassigned。分配列表后,必须对其进行设置。

  2. 正如@Kartik在评论中指出的那样,可能存在可见性问题,其他线程可能看不到所做的更改。标记列表和isReassigned volatile 即可解决此问题。