文章目录
- 1.volatile的应用
- 2.synchronized的原理与应用
- 3.原子操作的实现原理
- (1)处理器实现原子操作
- (2)Java实现原子操作
- 写在最后
简介:
java并发的底层主要还是涉及到了两位“大哥”——
volatile 和
synchronized。下面我们来了解一下:
1.volatile的应用
- **它在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。
- volatile原理:由有volatile修饰的变量汇编代码中会多出Lock前缀的指令。有以下两条原则:
- Lock前缀指令会引起处理器缓存回写到内存。
- 一个处理器的缓存回写到内存会导致其他处理器的缓存无效。
- **volatile的使用优化:**与处理器有关。
2.synchronized的原理与应用
Java SE 1.6中为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁,以及锁的存储结构和升级过程。
- synchronized基础:Java中的每一个对象都可以作为锁。具体表现为以下3种形式:
- 对于普通同步方法,锁是当前实例对象;
- 对于静态同步方法,锁是当前类的Class对象;
- 对于同步方法块,锁是Synchonized括号里配置的对象。
- 当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。
- synchronized用的锁存在Java的对象头里,这里设计到Java中类文件的知识。对象头里的Mark Word里默认存储对象的HashCode、分代年龄和锁标记位。
- 锁的升级:
- 偏向锁
- 轻量级锁
- 重量级锁
在Java内部实现了很多锁,除了偏向锁以外,JVM实现锁的方式都用了循环CAS。
3.原子操作的实现原理
我们都知道原子操作的意思是:“不可以被中断的一个或一系列操作”。我们先来了解一些术语:
- 缓存行:缓存的最小单位
- 比较与交换:CAS
- CPU流水线
- 内存顺序冲突
(1)处理器实现原子操作
处理器实现原子操作主要有两种方式,处理器不同方式也不同。
- 使用总线锁保证原子性
总线锁就是使用处理器提供的一个Lock # 信号,当总线上输出此信号时,其他处理器就会被阻塞。
就相当于有一个带大门的公共厕所(相当于总线),有一个人(处理器)上厕所了,把厕所是的大门锁上了(相当于提供Lock #),其他人(相当于其他处理器)就只能在外面等。
可想而知,这样的内存利用效率是很不高的,就相当于一个人每次只占一个坑,但是他却把大门锁住,别的坑无法有效的利用起来。所以就引出下面的缓存锁。 - 使用缓存锁保证原子性
简单的说就是,在执行锁操作回写到内存里面时,不在总线声言 Lock # 锁了(原因上面讲过了),而是修改内存地址,使得其他缓存行失效。
(2)Java实现原子操作
在Java中通过锁和循环CAS来实现原子操作
- 循环CAS的三大问题
- ABA
- 自旋时间过长,开销大
- 只能保证一个共享变量的原子操作
- 使用锁
在Java内部实现了很多锁,除了偏向锁以外,JVM实现锁的方式都用了循环CAS。
写在最后
如果觉得本文对你有帮助的话,可以为我点个赞哈,你的关注和支持是我坚持下去最大的鼓励。
对文章有什么建议和意见,也欢迎留言告诉我,期待你的回馈。