4

当没有同步块并且没有volatile变量时,由一个线程执行的写入何时对不同线程可见?这里是一个简化的快速排序例子:创建和连接线程时的副作用的可见性

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(); 

(为简单起见,假设两个“工作线程”不衍生任何额外的线程)

是否与两个线程加入保证当前线程看到了所有的副作用?


与此相关的,如果我初始分区之前创建的线程会发生什么?

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(); 

这两个线程是否能够看到由partitionForTheFirstTime()引起的副作用?换句话说,创建一个线程产生一个发生之前的关系,或者开始一个线程?

+0

创建一个线程对象不会创建一个线程,并且不会做太多工作。它只有当你开始()它创建一个真正的线程。 – 2011-06-07 10:41:39

回答

8

section 17.4.5 of the JLS

它遵循从上述定义:

  • 解锁在监视器之前发生该显示器上每个后续锁。
  • 在每次后续读取该字段之前,都会发生对易失性字段(第8.3.1.4节)的写入。
  • 在启动的线程中执行任何操作之前,会发生对线程启动()的调用。
  • 线程中的所有操作都会在任何其他线程从该线程上的join()成功返回之前发生。
  • 任何对象的默认初始化发生在程序的任何其他操作(非默认写入)之前。

该位约start()join()是给你的那些有关 - 换句话说,当你join() -ed一个线程成功,你会看到在该线程的所有操作。如果你线程start(),那个新线程将会看到在线程中已经发生的所有动作,这些动作调用start()

编辑:另见"memory consistency errors"

+0

我找到了完美的答案[这里](http://download.oracle.com/javase/tutorial/essential/concurrency/memconsist.html),也许你想加入?:) – fredoverflow 2011-06-08 10:46:22

0

除非您在执行start()之前执行partitionForTheFirstTime(),否则两个线程将对相同的数据进行操作。但是在这个例子中,通过将引用值传递给这些单独的线程,您需要谨慎。数组值通过引用传递,与通过值传递的原始值相反。结果两个线程将在同一个表上运行,这可能会导致竞争条件

+0

每个线程都对数组的一个不重叠的片段进行排序,所以它不应该是个问题,对吧? – fredoverflow 2011-06-07 11:25:45