volatile关键字
- 保证线程可见性
public class VolatileDemo {
/*volatile*/ boolean flag = true;
public void m() {
System.out.println("m start...");
while (flag) {
//do nothing
}
System.out.println("m end...");
}
public static void main(String[] args) {
VolatileDemo volatileDemo = new VolatileDemo();
new Thread(volatileDemo::m).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
volatileDemo.flag = false;
}
}
未加volitale:
m start…
加volitale:
m start…
m end…
原因: 如图所示,堆内存中存在flag的值为true,线程1、线程2分别拷贝了堆内存中的flag副本,然而当线程1改变了flag为false的时候,线程2是get不到flag的值为false,除了对变量加了volatile修饰
- MESI(缓存一致性协议)
- 禁止指令重排序
1.double check lock例子,一下是代码
代码
初始化时int类型的a
第一步:初始化为0
第二步:赋值,假设为8
第三步:将赋好的值给变量a
这三条指令,当不加volatile修饰a的时候,指令可能会重排序,导致的情况就是半初始化的时候,a=0,但是我们要的结果是a=8,这就造成意外的结果了
锁粗化 锁细化
锁细化:一般情况下,只对影响的代码做锁细化,例如count++等,其他没有多线程安全问题的可以不用加锁,这个称为锁细化
锁粗化:需要频繁的用到锁,如果锁太细反而影响性能,因此一般可以将锁粗化
CAS(无锁优化 自旋)
- Compare And Set
cas(V,Expected,NewValue)
if V == E
V = NewValue
otherwise try again or fail
CPU原语支持
- ABA问题
对引用类型会产生问题,对值类型不影响
1.加version
2.A 1.0
3.B 2.0
4.A 1.0
cas(version)