前言
本文主要内容关键字
Volatile
Synchrozied
一、关键字 Volatile
可见性:当一个线程修改一个共享变量时,另外一个变量能够读到这个修改的值。
内存屏障: 是一组处理器指令,用于实现对内存操作的顺序限制。
存在的问题:
a ++ 问题
非原子的64位操作(Long 和 Double 会将读或者写入分解成 32位的 两次操作)
如果一个字段被声明成了volatile ,java线程的内存模型确保所有线程看到这个变量的值是一致的。(它比synchronized的使用成本更低,因为它不会引起线程上文切换的的调度)
1.1 Volatile 是如何保证变量可见性的
通过在添加Lock指令
a.将当前处理器缓存行的数据协会到系统内存;
在多处理里,LOCK 信号一般不锁总线,而是锁缓存,毕竟锁总线的开销大;缓存一致性机制会阻止同事修改两个以上处理器缓存的内存区域数据
b.其他CPU里的该地址缓存 失效
MESI缓存一致性协议,将该地址设为 无效,其他缓存必须同步主存数据。也就是最新的数据
二、关键字 synchronized
相对于volatile来说,它是重量级锁,但是在1.6之后,引入了偏向锁 和 轻量级锁。
2.1 同步代码块
public void test () {
synchronized(Object.class){
}
}
实现原理是通过mointorenter 和monitorexit 指令实现的,他有一个监视器 mointorenter 。当获得锁后执行 mointorenter;释放一个锁后执行monitorexit指令。当进入非持有的锁时,mointor的数量要是 0;这个过程是排他的,同时只有一个线程获取到由synchronized所保护对象的监视器
2.2 同步方法
public synchronized void test(){
}
实现原理通过 ACC_SYNCHRONIZED指令 ;标有synchronized关键字的 方法字节码文件会有改指令
2.3小结
其实任意一个对象都拥有自己的监视器,当这个对象由同步块或者这个对象的同步方法d调用时,执行方法的线程必须先获取到该对象的监视器才能进入同步块或者同步方法。否者会被阻塞,进入 BLOLCKED状态,进入阻塞队列,等待唤醒。
参考资料
《JAVA 并发编程实战》
《JAVA并发编程的艺术》