1. AQS基本属性
- CAS算法:
CAS, CPU指令,在大多数处理器架构,包括IA32、Space中采用的都是CAS指令,CAS的语义是“我认为V的值应该为A,如果是,那么将V的值更新为B,否则不修改并告诉V的值实际为多少”,CAS是项乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。- 核心接口:
getState()
setState()
compareAndSetState() isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。
tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。
tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
tryReleaseShared(int):共享方式。尝试释放资源,成功则返回true,失败则返回false。
- 状态位
private volatile int state;
获得锁标识,通过调用Unsafe.compareAndSwapInt()实现。
- 获得锁的线程
private transient Thread exclusiveOwnerThread;
2. ReentrantLock
1. 非公平锁
- lock()
- 首先尝试把state由0置为1,如果成功把当前线程标记为exclusiveOwnerThread,如果失败进入2
- 当前线程形成Node对象,然后链至链表结尾。尝试获得锁,不成功阻塞(LockSupport.park(Thread),调用Unsafe.park())
- unlock()
找到链表的head,head是个空的Node,其next指向链表中第一个等待的线程,然后唤醒此线程(LockSupport.unpark(Thread),调用Unsafe.unpark())
默认情况下ReentrantLock为非公平锁,其原因有如下三条:
- 新的线程上来就尝试获得锁,有可能会获取成功,导致等待时间长的线程没有先执行。
- 新线程在第一次尝试获得锁失败后,在进入链表之前又尝试获得锁,有可能导致新线程提前执行。
- 线程被唤醒后尝试获得锁,有可能失败,导致被延迟执行。
2. 公平锁
与非公平锁最大的区别是当尝试获得锁时会先判断链表中是否有排队的线程,如果没有再尝试获得锁,这样可以保证按照链表的顺序执行线程,保证了一种公平。