创建和连接线程时副作用的可见性

时间:2011-06-07 10:21:17

标签: java multithreading concurrency synchronization memory-model

当没有同步块且没有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()引起的副作用?换句话说,创建一个线程会产生一个先发生过的关系,还是开始一个线程?

2 个答案:

答案 0 :(得分:8)

来自section 17.4.5 of the JLS

  

从以上定义得出:

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

关于start()join()的相关内容与您相关 - 换句话说,当您join()成功编写线程时,您会看到该主题中的所有操作。如果你start()一个线程,那个新线程将会看到调用start()的线程中已经发生的所有操作。

编辑:另见"memory consistency errors"

答案 1 :(得分:0)

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