Java多线程——Lock锁机制与AQS同步器
一、Lock锁总结
既然已经有个synchronized锁机制,为什么还要引入一个Lock锁机制?
1、Lock在synchronize基础上的改进
①synchronized是隐式获取释放锁
,但是将锁的获取和释放固化了,虽然简化了同步的管理,但扩展性不好,而lock体系缺拥有了锁获取与释放的可操作性(显式获取释放锁
)。
②synchronized内建锁有的功能Lock全有
。而Lock体系拥有可中断的获取锁
、超时获取锁
、共享锁
等(这些是内建锁不具备的特性)
③synchronized获取锁失败就进入阻塞状态(悲观锁机制),而lock获取锁失败就反复CAS自旋
(乐观锁机制)。
④synchronized可作用于代码块和函数上,而Lock锁只能作用于代码块上。
Lock锁机制与AQS同步器有什么关系?
2、Lock接口与AQS的关系
Lock接口的最主要实现类 ReentrantLock中所有的方法实际上都是调用了其静态内部类Sync中的方法。
Sync继承了AbstractQueuedSynchronizer(AQS-“同步器”),也就是说,Lock锁的整个体系是基于AQS同步器实现的
。
Lock锁在可中断获取锁、超时获取锁、共享锁是怎么实现的?
3、lock体系加强
synchronized的功能
①独占锁特性
a)获取锁时响应中断:acquireInterruptibly()
1> 获取锁时响应中断原理与acquire()几乎一样,与之唯一的区别在于当方法parkAndCheckInterrupt()返回true时,表示线程阻塞时被中断,抛出中断异常后线程退出。
2> 而acquire()中的acquireQueued()中若parkAndCheckInterrupt()返回true,只是将interrupt状态设置为true
b)超时等待获取锁:tryAcquireNanos()
该方法在三种情况
下会返回
1> 在超时时间内,当前线程成功获取到锁,返回true
2> 当前线程在超时时间内被中断,线程抛出异常
3> 超时时间结束,仍未获取到锁,线程退出返回false
超时获取锁逻辑与可中断获取锁基本一致,唯一区别在于获取锁失败后,增加了一个时间处理,如果当前时间超过截止时间,线程不再等待,直接退出,返回false。否则将线程阻塞置为等待状态排队获取锁。
②独占(互斥)锁与共享锁的特点
a)共享式访问资源时,其他共享式的访问均被允许,而独占式访问被阻塞。
b)独占式访问资源时,同一时刻其他所有访问均被阻塞。
既然AQS同步器是整个Lock体系的绝对核心,那到底什么是AQS同步器呢?
二、AQS同步器简介
1、AQS(队列)同步器简介
AQS(队列)同步器是用来构建锁以及其他同步组件的基础框架,它的实现主要是依赖一个int型的状态变量(锁的状态变量)以及通过一个FIFO队列共同构成同步队列。
Lock锁或者其他同步组件(包括自定义同步组件)是如何实现AQS的?
2、AQS的模板模式
AQS使用模板方法模式,将一些与状态相关
的核心方法开放给子类重写,而后AQS会使用子类重写的关于状态的方法进行线程的排队、阻塞以及唤醒等操作。
同步器即支持独占锁,也支持共享锁。
什么是独占锁?而什么又是共享锁?
独占锁:同一时刻只能有一个线程获取到该锁,其他想要获取锁的线程只能处于同步队列中等待。(只有当前线程释放了锁,同步队列中的线程才能获取锁)
共享锁:同一时刻有多个线程获取同步状态。
AQS提供的模板方法大体分为哪些呢?