Java: 在 Thread.start() 之前和之后对变量的更新。

huangapple go评论71阅读模式
英文:

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){
        // 打印 s1
        }
    }
}

现在当我写下如下代码

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

我希望 classB 中的 run() 方法打印出列表中的所有元素即在这种情况下为 (1, 2, 3)

这总是默认的吗还是我们需要应用多线程的概念才能实现

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

如果我在 A.start() 之后再添加另一个元素比如 A.addString("4")),那么为了使新线程打印出所有 4 个元素我应该怎么做
英文:

I have two classes

classA {
    private ArrayList&lt;String&gt; list = new ArrayList();

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

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

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

Now when I write code as

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

I want run() in classB to print all elements in list. i.e (1, 2, 3) in this case.

Is this always default or do we need to do apply multi threading concepts to make it happen?

What if list is non-volatile? Can new thread see all the elements (1,2,3)

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?

答案1

得分: 2

如果在启动另一个线程(ClassB)之前添加所有元素,则是安全的。《Java 语言规范 §17.4.4》(https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4.4) 中提到:
> 启动线程的操作与所启动线程中的第一个操作之间具有同步关系。

而且,同步关系 在《Java 语言规范 §17.4.5》中有定义:
> 如果操作 x 与后续操作 y 具有同步关系,那么我们也有 hb(x, y)

<sup>(hb(x, y) = x 发生在 y 之前)</sup>

因此,这确保了在读取和打印元素之前添加元素的操作是在其之前发生的。

然而,对于你当前的代码,如果你在从主线程启动另一个线程之后添加元素,则无法保证线程安全性,并且行为是不确定的。另一个线程可能会看到新增的元素,但也可能看不到,甚至可能因为它在不一致的状态下看到 ArrayList 的数据而抛出异常。


> 如果我在 A.start() 之后再添加另一个元素(比如 A.addString("4")),那么如何确保新线程打印出所有 4 个元素?

根据你的示例代码很难回答这个问题,因为代码的行为不太清楚:

  • 另一个线程(ClassB)是否应该无限期地等待新元素?这种情况下的一个解决方案可能是使用 BlockingQueue,或者使用某种信号机制,并且需要使用线程安全的集合(或同步访问 ArrayList)。
  • 如果另一个线程(ClassB)在打印旧元素之前已经完成,是否允许它忽略新元素?这种情况下只需要使用线程安全的集合(或同步访问 ArrayList)。

...

英文:

If you add all elements before starting the other thread (ClassB) it is safe. The JLS §17.4.4 says:
> An action that starts a thread synchronizes-with the first action in the thread it starts.

And synchronizes-with is defined in §17.4.5.:
> If an action x synchronizes-with a following action y, then we also have hb(x, y).

<sup>(hb(x, y) = x happens-before y)</sup>

So this guarantees that adding the elements happens-before reading and printing the elements.

However, with your current code, if you add elements from the main thread after you started the other thread, then you will have no thread-safety guarantees and the behavior is undefined. The other thread might see the added elements, but it could also not see them or possibly even throw an exception because it sees the data of the ArrayList in an inconsistent state.


> 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?

This is difficult to answer with your example code because it is not clear how the code should behave:

  • Should the other thread (ClassB) wait indefinitely for new elements? Then one solution could be using a BlockingQueue or using some sort of signaling and using a thread-safe collection (or synchronizing access to the ArrayList) is required.
  • Is the other thread (ClassB) allowed to miss the new elements in case it has finished printing the old elements before the new ones are added? Then only using a thread-safe collection (or synchronizing access to the ArrayList) is necessary.
  • ...

huangapple
  • 本文由 发表于 2020年9月5日 00:05:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/63744591.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定