背景
为了提升锁性能引入了 锁粗化技术。
锁粗化:
多个同步都加统一个对象。反复不停进出一个对象。JVM会对这样的代码进行逃逸分析。对整个代码块进行扫描。如果符合这种特征代码的话,会将多个同步块合并成一个大的同步快,变粗了。
锁消除:
如果对象不可能被多个对象访问到。通过逃逸分析,会对锁进行消除。比如只加在对象上的锁。对象的生命周期是线程调用周期,对象只被一个线程访问。此时会对锁进行消除。
还有一个典型的就是栈上分配的对象,符合逃逸分析的对象,分配在栈上。并且对这个对象进行了加锁。此时,也只有这个线程能对对象进行访问,就会进行锁消除。
PS:逃逸分析后会做的优化:锁消除,锁粗化,标量替换等。
标量:八大基本类型。
AQS LOCK详解
- AQS还没出现之前,如果需要规定一个线程占用CPU使用时间的话,可能用到while循环。
或者用:lock.pack(); lock.Unpack(THread) 停止,阻塞方法。
unpack
CAS
Lock三大核心:自旋,LockSupport,CAS,队列
队列的FIFO用来实现公平,非公平锁。
CAS依赖硬件元语:cmpxchg()
LockSupport:线程阻塞工具。底层是native的方法 UNSAFE.xx
AQS具备特性:
- 阻塞等待队列
- 共享/独占
- 公平/非公平
- 可重入
- 允许中断
除了Lock外,Java.concurrent.util当中同步器的实现如Latch,Barrier,BlockingQueue等, 都是基于AQS框架实现
AQS内部维护属性volatile int state (32位)
state表示资源可用状态。
- state三种访问方式:
- getState()
- setState(int)
- compareAndSetState()
- AQS定义两种资源共享方式
- Exclusive-独占,只有一个线程能执行,如ReentrantLock。
- Share-共享,多个线程可以同时执行,如Semaphore/CountDownLatch。
- 同步等待队列
- 同步等待队列
- 不同的自定义同步器争用共享资源的方式也不同。自定义同步器在实现时只需要实现共 享资源state的获取与释放方式即可,至于具体线程等待队列的维护(如获取资源失败入队/ 唤醒出队等),AQS已经在顶层实现好了。自定义同步器实现时主要实现以下几种方法:
- isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去 实现它。
- tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回 false。
- tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回 false。
- tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成 功,但没有剩余可用资源;正数表示成功,且有剩余资源。