Java内存模型规定了所有的变量都存储在主内存(Main Memory)中。每条线程 还有自己的工作内存(Working Memory),线程的工作内存中保 存了被该线程使用的变量的主内存副本,线程对变量的所有操作(读取、赋值等)都必须在工作内 存中进行,而不能直接读写主内存中的数据。
不同的线程之间也无法直接访问对方工作内存中的变 量,线程间变量值的传递均需要通过主内存来完成。
Java内存模型中定义了以下8种操作来完成
lock(锁定):作用于主内存的变量,它把一个变量标识为一条线程独占的状态。
unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量 才可以被其他线程锁定。
read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以 便随后的load动作使用。
load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的 变量副本中。
use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚 拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作。
assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收的值赋给工作内存的变量, 每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。 ·store(存储):作用于工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便随 后的write操作使用。
write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的 变量中。
这里的lock,unlock说的是内存模型,和代码中lock接口没关系
Java内存模型还规定了在执行上述8种基本操作时必须满足如下规则:
最新的JSR-133文档中,已经放弃了采用这8种操作去定义Java内存模 型的访问协议,缩减为4种(read、write、lock和unlock)(仅是描述方式改变了,Java内存模型并没有改变)。
Java内存模型是围绕着在并发过程中如何处理原子性、可见性和有序性这三个特征来建立的
原子性(Atomicity)
由Java内存模型来直接保证的原子性变量操作包括read、load、assign、use、store和write这六个.基本数据类型的访问、读写都是具备原子性的(例外就是long和double的非原子性协定,不用太在意,几乎不会发生)。
更大范围的原子性保证,提供了lock和 unlock操作来满足这种需求,对应synchronized关键字相关的字节码指令monitorenter和monitorexit。因此在synchronized块之间的操作也具备原子性。
可见性(Visibility)
volatile保证了新值 能立即同步到主内存,以及每次使用前立即从主内存刷新
同步块的可见性是由“对一个变量执行unlock操作之前,必须先把此变量同步回主内存中(执行store、write操 作)”这条规则获得的。
而inal关键字的可见性是指:被final修饰的字段在构造器中一旦被初始化完 成,并且构造器没有把“this”的引用传递出去(没有发生this引用逃逸),那么在其他线程中就能看见final字段的值。
有序性(Ordering)
Java程序中天然的有序性可以 总结为一句话:如果在本线程内观察,所有的操作都是有序的;如果在一个线程中观察另一个线程, 所有的操作都是无序的。
volatile关键字包含了禁止指令重排序的语义
synchronized则是由“一个变量在同一个时刻只允许一条线程对 其进行lock操作”这条规则获得的,这个规则决定了持有同一个锁的两个同步块只能串行地进入
Java内存模型下一些“天然的”先行发生(Happens-Before关系,这些先行发生关系无须任何同步器协助就已经存在,可以在编码中直接使用。如果两个操作之间的关系不在此列,并且无法从下列规则推导出 来,则它们就没有顺序性保障,虚拟机可以对它们随意地进行重排序。
Java语言定义了6种线程状态
新建(New):创建后尚未启动的线程处于这种状态。
运行(Runnable):包括操作系统线程状态中的Running和Ready,也就是处于此状态的线程有可 能正在执行,也有可能正在等待着操作系统为它分配执行时间。
无限期等待(Waiting):处于这种状态的线程不会被分配处理器执行时间,它们要等待被其他线 程显式唤醒。以下方法会让线程陷入无限期的等待状态:
没有设置Timeout参数的Object::wait()方法;
没有设置Timeout参数的Thread::join()方法;
LockSupport::park()方法。
限期等待(Timed Waiting):处于这种状态的线程也不会被分配处理器执行时间,不过无须等待 被其他线程显式唤醒,在一定时间之后它们会由系统自动唤醒。以下方法会让线程进入限期等待状 态:
Thread::sleep()方法;
设置了Timeout参数的Object::wait()方法;
设置了Timeout参数的Thread::join()方法;
LockSupport::parkNanos()方法;
LockSupport::parkUntil()方法。
阻塞(Blocked):线程被阻塞了,“阻塞状态”与“等待状态”的区别是“阻塞状态”在等待着获取到 一个排它锁,这个事件将在另外一个线程放弃这个锁的时候发生;而“等待状态”则是在等待一段时 间,或者唤醒动作的发生。在程序等待进入同步区域的时候,线程将进入这种状态。
结束(Terminated):已终止线程的线程状态,线程已经结束执行。
转换关系