同步
基础
- volatile
1)保证可见性,被修饰的变量的写操作会立刻同步到主内存,每次使用被修饰的变量都要在主内存读取。
2)禁用指令重排,虚拟机保证同线程内的执行顺序产生的效果等同于顺序执行,但对于不同线程来说不做出类似保证,使用volatile修饰的变量前的操作和后面的操作一定会按照先后顺序发生。
3)无法保证操作的原子性,应该注意i=i+1这种操作即使i被volatile修饰也无法保证原子性。
保证可见性和禁用指令重排通过内存屏障实现
内存屏障有两个作用:
1)阻止屏障两侧的指令重排序
2)强制把写缓冲区/高速缓存中的数据写回主内存
- AbstractQueuedSynchronizer
java同步功能的重要基础,大多数同步API都基于此类。
1)独占模式:用于实现锁,大多数的锁都是基于此,内部使用双向链表保存节点,节点状态为独占,每次尝试CAS状态量获取执行权,如果失败CAS尾节点入队。
2)共享模式:用于读写锁、同步工具的实现等,共享模式下节点状态为共享,获取执行权的同时会尝试唤醒后续共享状态的节点。
锁
- synchronized
监视器锁,性能不错,功能比较少,可重入,用起来简单,加锁过程如下:
1)尝试获取偏向锁,如果被人捷足先登,瞅一眼他的状态,如果他用完了或者死掉了,偏向当前线程,如果他还在用,给他办个轻量级锁,尝试cas获取轻量级锁。
2)虚拟机有俩参数,一个是是否开启自适应自旋升级重量级锁次数,另一个是自旋次数,如果前者开启,虚拟机会决定自旋多少次升级为重量级锁,如果关闭,则根据后者。尝试获取轻量级锁失败后会自旋一定的次数,如果自旋后尝试获取还是失败了,那就升级重量级锁。
3)如果有一个线程申请轻量级锁失败了,这时候又来了一个,二者都会升级为重量级锁,因为这时候意味着这个锁竞争压力大了。 - ReentrantLock
最常用的Api锁,功能丰富,支持公平模式,可重入
使用AQS实现 - ReentrantReadWriteLock
可重入的读写锁,AQS共享锁实现 - StampedLock
不可重入的读写锁,提供了乐观锁实现方法,没有实现Lock接口
工具
- CountDownLatch
线程屏障,基于AQS的共享锁实现 - Semaphore
信号量,基于AQS的共享锁实现,可选公平模式
几乎是最好用的工具,yes! - CyclicBarrier
基于Condition实现,可循环使用 - Phaser
灵活的可复用的可动态调整的CyclicBarrier
原子
- AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference
基于Unsafe进行CAS - AtomicMarkableReference
避免ABA问题,使用Pair类标识修改信息, - AtomicStampedReference
避免ABA问题,与AtomicMarkableReference不同的是该类使用boolean值表明是否有过修改 - AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
这里名叫包装类型,实际上内部创建的是基本类型数组,注意默认值的问题 - AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater
依然是CAS,获取Unsafe然后初始化时获取偏移量,后续CAS - LongAccumulator、LongAdder、DoubleAccumulator、DoubleAdder
Accumulator为根据自定义合并函数计算,Adder仅为加法,内置Cell数组,当base(实际值)竞争激烈时将应计算数值存入Cell数组,获取值的时候进行全部计算。
其他
- 乐观锁
CAS是最典型的乐观思想,本质上没有乐观锁,可以用乐观实现实现的同步工具还是有的,比如读写锁,比如某些原子类的实现。