简体   繁体   English

创建和加入线程时副作用的可见性

[英]visibility of side effects when creating and joining threads

When are writes that are performed by one thread visible to a different thread when there are no synchronized blocks and no volatile variables?当没有同步块和易失性变量时,一个线程执行的写入何时对另一个线程可见? Here is a simplified quicksort example:这是一个简化的快速排序示例:

int middle = partitionForTheFirstTime(array);

Thread t = new Thread(new Quicksorter(array, 0, middle - 1));
Thread u = new Thread(new Quicksorter(array, middle + 1, array.size - 1));

t.start()
u.start();

t.join();
u.join();

(For the sake of simplicity, assume that the two "worker threads" do not spawn any additional threads.) (为了简单起见,假设两个“工作线程”不产生任何额外的线程。)

Does joining with the two threads guarantee that the current thread sees all their side effects?加入这两个线程是否保证当前线程看到它们的所有副作用?


On a related note, what would happen if I created the threads before the initial partitioning?在相关说明中,如果我在初始分区之前创建线程会发生什么?

Quicksorter a = new Quicksorter();
Quicksorter b = new Quicksorter();

Thread t = new Thread(a);
Thread u = new Thread(b);

int middle = partitionForTheFirstTime(array);

a.setParameters(array, 0, middle - 1);
b.setParameters(array, middle + 1, array.size - 1);

t.start()
u.start();

t.join();
u.join();

Will the two threads be able to see the side effects caused by partitionForTheFirstTime() ?两个线程能否看到partitionForTheFirstTime()引起的副作用? In other words, does creating a Thread incur a happens-before relationship, or does starting a Thread?换句话说,创建线程是否会产生先发生关系,还是启动线程?

From section 17.4.5 of the JLS :JLS 的第 17.4.5 节

It follows from the above definitions that:从上面的定义可以得出:

  • An unlock on a monitor happens-before every subsequent lock on that monitor.监视器上的解锁发生在该监视器上的每个后续锁定之前。
  • A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.对 volatile 字段(第 8.3.1.4 节)的写入发生在对该字段的每次后续读取之前。
  • A call to start() on a thread happens-before any actions in the started thread.线程上的 start() 调用发生在已启动线程中的任何操作之前。
  • All actions in a thread happen-before any other thread successfully returns from a join() on that thread.线程中的所有操作都发生在任何其他线程从该线程上的 join() 成功返回之前。
  • The default initialization of any object happens-before any other actions (other than default-writes) of a program.任何 object 的默认初始化发生在程序的任何其他操作(默认写入除外)之前。

The bits about start() and join() are the relevant ones for you - in other words, when you've join() -ed a thread successfully, you see all actions in that thread.关于start()join()的部分与您相关 - 换句话说,当您成功join() -ed 线程时,您会看到该线程中的所有操作。 If you start() a thread, that new thread will see all the actions which have already occurred in the thread which calls start() .如果您start()一个线程,该新线程将看到调用start()的线程中已经发生的所有操作。

EDIT: Also see "memory consistency errors" .编辑:另见“内存一致性错误”

Unless you execute start() prior executing partitionForTheFirstTime() both threads will operate on the same data.除非您在执行 partitionForTheFirstTime() 之前执行 start(),否则两个线程都将对相同的数据进行操作。 But you need to be carefull in terms of passing referential values to these separate threads in this example the array value is passed by reference in opposite to primitive values which are passed by value.但是在此示例中,在将引用值传递给这些单独的线程时需要小心,数组值是通过引用传递的,与通过值传递的原始值相反。 As a result both threads will operate on the very same table and this may cause race conditions结果,两个线程都将在同一张表上运行,这可能会导致竞争条件

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM