并发编程的挑战
- 上下文切换;
- 死锁问题:避免一个线程同时获取多个锁;避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源;尝试使用定时锁;
- 资源限制:并发编程,执行速度受限于硬件资源和软件资源;
并发编程的底层原理
volatile的应用(轻量级的synchronized)
定义:保证共享变量的“可见性”,当一个线程修改一个变量时,另外一个线程能读到这个修改的值;
volatile的两条实现原则:
- Lock前缀指令会引起处理器缓存会写到内存;
- 一个处理器的缓存回写到内存会导致其它处理器的缓存无效;
volatile的优化:通过一种追加字节的方式优化队列的出队和入队的性能;
原因:一些处理的高速缓冲行是64个字宽,不支持部分缓冲行,即队列的头结点和尾节点都不足64字节的话,处理会将它们都读到一个高速缓冲中,在多处理器每个处理器都会缓存同样的头尾节点,当一个处理器试图修改头节点时,会将整个缓冲行锁定,那么在缓存一致性的作用下,导致其他处理器不能访问自己高速缓存中的尾节点,影响效率;
不适用的场景:
- 缓冲行非64字节宽的处理器;
- 共享变量不会被频繁的写;
synchronized的实现原理与应用(重量级)
形式:
- 对于普通方法,锁是当前实例对象;
- 对于静态同步方法,锁是当前类的Class对象;
- 对于同步方法块,锁是Synchronized括号里配置的对象;
锁的优缺点对比:
锁 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
偏像锁 | 加锁和解锁不需要额外的消耗,和执行非同步的方法相比仅存在纳米级的差距 | 线程间存在锁竞争,会带来额外的锁撤销的消耗 | 一个线程访问同步块的场景 |
轻量级锁 | 竞争的锁不会阻塞,提高了程序的响应速度 | 如果始终得不到锁竞争的线程,使用自旋会消耗CPU | 追求响应时间 同步块执行速度非常快 |
重量级锁 | 线程竞争不使用自旋,不会消耗CPU | 线程阻塞,响应时间缓慢 | 追求吞吐量 同步块执行速度较长 |
原子操作的实现原理
定义:不可被中断的一个或一系列操作;
实现机制:通过总线锁保证原子性;通过缓存锁保证原子性;
java中实现原子操作:通过锁和循环CAS的方式;
CAS的问题:
- ABA问题;
- 循环时间长开销大;
- 只能保证一个共享变量的原子操作;