1. 介绍  

  JVM支持多个线程执行。在Java中由一个叫Thread的类来扮演线程。只有通过这个类的实例来开启一个线程,每个线程都会关联这么一个对象。当这个Thread的实例的start方法被调用时,标志着一个线程会被开启。线程的表现特别是在没有被设置同步时会使人感觉疑惑和不解。本规范会解释在JLS中描述的多线程程序的表,包括在一个共享内存上正在被线程修改的值该显示为多少的规则。在内存模型上本规范和很多硬件架构相似,这些语义在JMM上会被描述。

  这些语义不是描述一个多线程程序应该怎么执行,而是描述多线程程序允许怎么呈现多线程特性。一种多线程的实现必须遵守本规范允许的实现策略。

2. 锁

  有很多线程间交流的机制。大部分都是基于使用监视器的同步机制,每个线程对象都会关联一个监视器来实现占有或释放资源。对于同一个监视器,同一时间只能有一个线程能够占有这个资源,而其他线程只有等上一个线程将改资源释放后才能占有这个资源。一个线程可能会占有一个监视器多次,每个lock操作都会撤销一个unlock操作。synchronized 申明都会被指向某个对象,并企图在这个对象的监视器上加一个锁,这个行为会一直堵塞在这步直到这个行为成功完成。当synchronized 被成功申明后,synchronized的主体会被执行。如果主体被执行完成或者意外退出,unlock这个监视器的行为就会被自动执行。

  一个被synchronized修饰的方法在被调用时会被自动加锁,该方法的主体只有在加锁完成后才能执行。如果这个方法是实例方法,会锁住这个被调用的对象的监视器(也就是在方法执行中,我们通常叫的this),如果方法被static修饰,那么锁住的就是这个static方法所在的Class对象的监视器。如果方法的主题成功执行完成或者因为某些原因以外中断,那么在这个监视器上会自动执行unlock操作。

  这种语义不会阻止和侦察死锁的情况。线程中的程序(直接或者间接地)持有多个对象的锁,应该使用一些技术手段避免死锁的出现,如果必须需要创建一些高级别的锁语义。

  其他的一些机制,volatile修饰的变量的读写以及在java.util.concurrent中提供的类,实现了一些非传统的同步机制。

3. 实例中的表示法

  java内存模型从根本上讲没有遵循JLS的面向对象的特征。在我们的例子中为了简洁和简单,我们只呈现代码片段而没有完整的方法定义、类定义和明确的引用(import ...),大多数实例都是考虑多个线程访问本地变量或者是实例对象的属性。我们用使用典型的变量名称如,r1,r2来表示方法或者线程中的变量,这些变量其他线程不能访问。