内存交互操作
- lock
作用于主内存的变量,把变量标识为一条线程独占的状态 - unlock
作用于主内存的变量,把处理锁定状态的变量释放 - read
作用于主内存的变量,把变量从主内存传输到线程的工作内存中 - load
作用于工作内存的变量,把read操作从主内存得到的变量放入工作内存的变量副本中 - use
作用于工作内存的变量,把工作内存的变量值传递给执行引擎 - assign
作用于工作内存的变量,把一个执行引擎接受的值赋值给工作内存的变量 - store
作用于工作内存的变量,把工作内存中一个变量的值传送到主内存中 - write
作用于主内存的变量,把store的变量放入主内存的变量中
变量从主内存复制到工作内存:read->load
变成从工作内存同步回住内存:store->write
操作规则:
- read和load、store和write必须成对出现
- 变量在工作内存中改变了之后必须把该变化同步回主内存中
- 必须发送了assign操作,才能把数据同步回主内存中
- 新变量只能在主内存中诞生
- 一个变量在同一时刻只允许一条线程对其进行lock操作,但可以被同一个线程重复执行多次。
- 如果对一个变量执行了lock,则必须清空工作内存中此变量的值
- lock,unlock必须顺序出现
- 执行unlock操作前,必须先把变量同步回主内存中
volatile 变量的特殊规则
当一个变量定义为volatile后,他有两个特性
保证此变量对所有线程的可见性,当一个线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的(volatile变量也可以存在不一致的情况,但是由于每次使用之前都会先去刷新,因此可以认为不存在不一致问题)
由于volatile变量只能保证可见性,在不符合以下两条规则的运算场景中,我们任然要通过加锁来保证原子性。
1.运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量值。(i++)
2.变量不需要与其他的状态变量共同参与不变约束。
//合适使用volatile 的 ,只要shutDown一改变,就能保证所有线程执行doWrok方法立即停止
volatile boolean shutDown;
public void doWork(){
while(!shutDown){
//do
}
}
- 禁止指令重排序优化
指:可以重排没有依赖关系的指令
Java线程
实现线程的3中方式
- 使用内核线程实现
直接由操作系统内核支持的线程,由内核完成线程的切换。
程序一般不会直接去使用内核线程,而是去使用内核线程的一种高级接口——轻量级进程,每个轻量级进程都由一个内核线程支持。
缺点:1.线程操作(创建。。。。)都需要系统调度,代价高;2.每个进程都需要内核线程的支持,需要消耗一定的内核资源,因此数量是有限的 - 使用用户线程实现
完全建立在用户空间的线程库上,系统内核不能感知线程存在的实现。线程操作完全在用户态中完成,不需要内核的帮助
优点:不需要系统内核的支援
缺点:所以线程都需要用户程序自己处理。程序实现复杂 - 使用用户线程加轻量级进程混合实现
混合方式,既存在用户线程,也存在 轻量级进程。完成建立在用户空间,线程操作依然廉价,操作系统提供的轻量级进程则作为用户线程和内核线程之间的桥梁,这样可以使用内核提供的线程调度功能以及处理器映射。 - java线程实现
JDK1.2前使用基于称为“绿色线程”的用户线程实现的,1.2以后替换为基于操作系统原生线程模型实现。
Sun JDK来说,它的Windows版本与Linux版本都是使用一对一的线程模型实现的,一条Java线程就映射到一条轻量级进程中,因为Windows和Linux系统提供的线程模型就是一对一的