1. 显示锁 Lock
lock 接口可以提供一些sychnoized 不具备的一些其他特性 如:
1。 尝试非阻塞去获取锁
2. 可以被终端的获取锁
3. 超时获取锁
lock 接口的核心方法
lock():获取锁, 类似sychnonized 关键字
unlock():释放锁(当退出synchnonized 关键字所包围的代码块的时候, 锁自动释放)
tryLock(): 尝试非阻塞的去获取锁, 获得锁返回true, 没有返回false
显示锁的使用方法
Lock lock = new ReentranLock()
lock.lock()
try{
do sth…
}finally{
lock.unlock();
}
2. 排它锁
排它锁在同一时刻只允许一个线程访问
3. 读写锁
ReadWriteLock lock = new ReentrantReadWriteLock()
Lock getLock = lock.readLock()// 读锁
Lock setLock = lock.writeLock()// 读锁
代码示例:
比synchnonized 锁更快
4. Condition 接口
lock 接口不能和wait notify 等方法相结合实现等待。 所以有了condition 接口实现等待和通知
使用方法:
Lock kmlock= new ReentrantReadWriteLock()
Condition kmcond= kmlock.newCondition();
kmcond.signal(); kmcond.signalAll(); 通知其他在锁上等待的线程。 尽量使用signal, 因为知道是哪个锁, 只通知这个锁上的线程即可
kmcond.await()// 当前线程进行等待
代码示例:
5. CAS (Compare And Swap)操作:
比较并且交换。 三个运算符: 一个内存地址v, 一个期望的旧值A, 一个新值B
检查内存地址V 上的值, 是不是期望的A 值, 如果是, 就把地址v的变成B, 如果不是A , 则V 的值不变
CAS 带来的问题:
- ABA : 地址V 的值从 A–》C–>A 时, 我们检查的时候, 发现A-A 没有变, 但实际上C 已经过去了, 它的值已经变了, 不是原来的A 了
解决: 版本号:1A–》2C–>3A 来控制
使用AtomicStampedReference 自带版本戳原子操作类
示例代码:
2. 循环时间长, 开销大
3. 往往只能保证一个共享变量的原子操作
示例代码:
ai.getAndIncrement(), get 在前, 表示, 先返回变量里面已有的值, get 在后返回变量操作完之后的新值