-
volatile 是如何来保 证 可 见 性?
如果
对
声明了
volatile
的
变
量
进
行 写 操作,
JVM
就会向
处
理器
发
送一条
Lock
前
缀
的指令,将
这
个
变
量所在
缓
存行的数据
写回到系
统
内存。
每个
处
理器通
过
嗅探在
总线
上
传
播的数据来
检查
自己
缓
存的
值
是不是
过
期了,当
处
理器
发现
自己
缓
存行
对应
的内存地址被修改,就会将当前
处
理器的
缓
存行
设
置成无效状
态。
当
处
理器
对这
个数据
进
行修改操作的
时
候,会重新从系
统
内存中把数据
读
到
处
理器
缓
存
里。
-
Synchonized 在 JVM 里的 实现 原理?
JVM
基于
进
入和退出
Monitor
对
象来
实现
方法同步和代
码块
同步
代
码块
同步是使用
monitorenter
和
monitorexit
指令
实现
的
monitorenter
指令是在
编译
后插入到同步代
码块
的开始位置,而
monitorexit
是插入到方法
结
束
处
和异常
处
,
JVM
要保
证
每个
monitorenter
必
须
有
对应
的
monitorexit
与之配
对
。任何
对
象都有
一个
monitor
与之关
联
,当且一个
monitor
被持有后,它将
处
于
锁
定状
态
。
线
程
执
到
monitorenter
指令
时
,将会
尝试获
取
对
象所
对应
的
monitor
的所有
权
,即
尝试获
得
对
象的
锁
。
happens-before
规则
1
)程序
顺
序
规则
:一个
线
程中的每个操作,
happens-before
于
该线
程中的任意后
续
操作。
2
)
监视
器
锁规则
:
对
一个
锁
的解
锁
,
happens-before
于随后
对这
个
锁
的加
锁
。
3
)
volatile
变
量
规则
:
对
一个
volatile
域的写,
happens-before
于任意后
续对这
个
volatile
域的
读
。
4
)
传递
性:如果
A happens-before B
,且
B happens-before C
,那么
A happens-before C
。
5
)
start()
规则
:如果
线
程
A
执
行操作
ThreadB.start()
(启
动线
程
B
),那么
A
线
程的
ThreadB.start()
操作
happens-before
于
线
程
B
中的任意操作。
6
)
join()
规则
:如果
线
程
A
执
行操作
ThreadB.join()
并成功返回,那么
线
程
B
中的任意操作
happens-before
于
线
程
A
从
ThreadB.join()
操作成功返回。
public class SafeDoubleCheckedLocking {
private volatile static Instance instance;
public static Instance getInstance() {
if (instance == null) {
synchronized (SafeDoubleCheckedLocking.class) {
if (instance == null)
instance = new Instance(); // instance为volatile,现在没问题了
}
}
return instance;
}
}
对实
例字段使用
线
程
安全的延
迟
初始化,
使用
基于
volatile
的延
迟
初始化的方案
对
静
态
字段使用
线
程安全的延
迟
初始化,
使用
基于
类
初始化的方案
public class InstanceFactory {
private static class InstanceHolder {
public static Instance instance = new Instance();
}
public static Instance getInstance() {
return InstanceHolder.instance ; // 这里将导致InstanceHolder类被初始化
}
}
中断可以理解
为线
程的一个
标识
位属性,它表示一个运行中的
线
程是否被其他
线
程
进
行
了中断操作。中断好比其他
线
程
对该线
程打了个招呼,其他
线
程通
过调
用
该线
程的
interrupt()
方法
对
其
进
行中断操作。
线
程通
过检查
自身是否被中断来
进
行响
应
,
线
程通
过
方法
isInterrupted()
来
进
行判断是否
被中断,也可以
调
用静
态
方法
Thread.interrupted()
对
当前
线
程的中断
标识
位
进
行复位。
如果
该
线
程已
经处
于
终结
状
态
,即使
该线
程被中断
过
,在
调
用
该线
程
对
象的
isInterrupted()
时
依旧会返
回
false
。
许
多声明抛出
InterruptedException
的方法(例如
Thread.sleep(long
millis)
方法)
这
些方法在抛出
InterruptedException
之前,
Java
虚
拟
机会先将
该线
程的中断
标识
位
清除,然后抛出
InterruptedException
,此
时调
用
isInterrupted()
方法将会返回
false
。
ThreadLocal
,即
线
程
变
量,是一个以
ThreadLocal
对
象
为键
、任意
对
象
为值
的存
储结
构。
这
个
结
构被附
带
在
线
程上,也就是
说
一个
线
程可以根据一个
ThreadLocal
对
象
查询
到
绑
定在
这
个
线
程上的一个
值
。
可以通
过
set(T)
方法来
设
置一个
值
,在当前
线
程下再通
过
get()
方法
获
取到原先
设
置的
值
。