Java并发编程——存储模型

存储模型明确地规定了在什么时机下,操作存储的线程的动作可以保证被另外的动作看到。规范还规定了要保证操作是按照一种偏序关系进行排序。这种关系称为happens-before,它是规定在独立存储器和同步操作级别之上的。

1、happens-before的法则包括:

程序次序法则:线程中每个动作A都happens-before于该线程中的每一个动作B,其中,在程序中,所有的动作B都出现在动作A之后。

监视器锁法则:对一个监视器锁的解锁happens-before于每一个后续对同一监视器锁的加锁。

volatile 变量法则:对volatile域的写入操作happens-before于每个后续对同一域的读操作。

线程启动法则:在一个线程里,对Tread.start的调用会happens-before于每一个启动线程的动作。

线程终结法则:线程中的任何动作都happens-beore于其他线程检测到这个线程已经终结、或者从Thread.join调用中成功返回,或者Thread.isAlive返回false。

中断法则:一个线程调用另一个线程的interrupt happens-before于被中断的线程发现中断(通过抛出InterruptedException,或者调用isInterrupted和interrupted)。

终结法则:一个对象的构造函数的结束happens-before于这个对象finalizer的开始。

传递性:如果A happens-before于B,且B happens-before 于C,则Ahappens-before于C。

由类库担保的其他happens-before排序包括:

  • 将一个条目置入线程安全容器happens-before于另一个线程从容器中获取条目。
  • 执行CountDownLatch中的倒计时happens-before于线程从闭锁(latch)的await中返回。
  • 释放一个许可给Semaphore happens-before于从同一Semaphore里获得一个许可。
  • Fure表现的任务所发生的动作happens-before于另一个线程成功地从Future.get中返回。
  • 向Executor提交一个Runnable或Callable happens-before于开始执行任务。

最后,一个线程达到CyclicBarrier或者Exchanger happens-before 于相同关卡或Exchange点中的其他线程被释放。如果CyclicBarrier使用一个关卡动作,到达关卡happens-before于关卡动作,依照次序,关卡动作happens-before于线程从关卡中释放。

2、发布

除了不可变对象以外,使用被另一个线程初始化的对象,是不安全的,除非对象发布是happens-before于对象的消费线程使用它

3、初始化安全性

初始化安全可以保证,对于正确创建对象,无论它是如何发布的,所有线程都将看到构造函数设置的final域的值。更进一步,一个正确创建的对象中,任何可以通过其final域触及到的变量(比如一个final数组中的元素,或者一个final域引用的HashMap里面的内容),也可以保证对其他线程都是可见的。   

初始化安全性保证只有以通过final域触及的值,在构造函数完成时才是可见的。对于通过非final域触及的值,或者创建完成后可能改变的值,必须使用同步来确保可见性。



留言