Java :更新 Thread.start() 前后的变量

Java : updates to variables before and after Thread.start()

我有两个类

classA {
    private ArrayList<String> list = new ArrayList();

    void addString(String s){
        list.add(s);
    }

    void start(){
        new ClassB(list).start();
    }
}

classB extends Thread{
    ArrayList<String> s;
    
    public ClassB(ArrayList<String> s) { this.s = s; }
    
    void run(){
        for (String s1 : s){
        // print s1
        }
    }
}

现在当我把代码写成

ClassA A = new ClassA();
A.addString("1");
A.addString("2");
A.addString("3");
A.start();

我希望 classB 中的 运行() 打印列表中的所有元素。即本例中的 (1, 2, 3)。

这始终是默认设置还是我们需要应用多线程概念才能实现?

如果列表是非易失性的呢?新线程能否看到所有元素 (1,2,3)

如果我在 A.start() 之后添加另一个元素怎么办(比如 A.addString("4") ),那么我应该怎么做才能让新线程打印所有 4 个元素?

如果在启动另一个线程 (ClassB) 之前 添加所有元素 它是安全的。 JLS §17.4.4 表示:

An action that starts a thread synchronizes-with the first action in the thread it starts.

synchronizes-with定义在§17.4.5.:

If an action x synchronizes-with a following action y, then we also have hb(x, y).

(hb(x, y) = x happens-before y)

所以这保证添加元素happens-before读取和打印元素

但是,对于您当前的代码,如果您在启动另一个线程之后从主线程添加元素,那么您将没有 thread-safety 保证并且行为未定义。另一个线程 可能 看到添加的元素,但它也可能看不到它们,甚至可能抛出异常,因为它看到 ArrayList 的数据处于不一致状态。


What if I add another element after A.start() (say A.addString("4") ), then what should I do to make new thread print all 4 elements?

这很难用您的示例代码来回答,因为不清楚代码的行为方式:

  • 另一个线程 (ClassB) 是否应该无限期地等待新元素?那么一种解决方案可能是使用 BlockingQueue 或使用某种信号并使用 thread-safe 集合(或同步访问 ArrayList)是必需的。
  • 是否允许另一个线程 (ClassB) 错过新元素,以防它在添加新元素之前完成旧元素的打印?然后只需要使用 thread-safe 集合(或同步访问 ArrayList)。
  • ...