RentrantLock关键字详解

简介: RentrantLock关键字详解

一、什么是AQS

全称是 AbstractQueuedSynchronizer(队列同步器,下文简称同步器),是阻塞式锁和相关的同步器工具的框架,它是构建锁或者其他同步组件的基础框架。【AQS是实现锁的关键,在锁的实现中聚合同步器,利用同步器实现锁的含义】


AQS的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理同步状态,重写同步器指定的方法时,AQS提供了3个方法访问或修改同步状态。


  • getState():获取当前同步状态


  • setState(int newState):设置当前同步状态


  • compareAndSetState(int expect,int update):使用CAS设置当前状态,保证状态设置的原子性


节点是构成同步队列的基础,同步器拥有首节点(head)和尾结点(tail),没有成功获取同步状态的线程将会成为节点加入该队列的尾部。同步器包含两类节点类型的引用:一个指向头节点,另一个指向尾结点。

同步器提供了一个基于CAS的设置尾结点的方法:compareAndSetState(int expect,int update),它需要传递当前线程“认为”的尾结点和当前节点,只有设置成功,当前节点才与之前的尾结点建立联系。

设置首节点是通过获取同步状态成功的线程来完成的,由于只有一个线程能成功获取到同步状态,因此,设置头节点不需要用CAS,只需要将首节点设置为原首节点的后继节点并断开原首节点的next引用即可。

AQS常见的实现类

  • ReentrantLock 阻塞式锁
  • Semaphore 信号量
  • CountDownLatch 倒计时锁

  • 新的线程与队列中的线程共同来抢资源,是非公平锁
  • 新的线程到队列中等待,只让队列中的head线程获取锁,是公平锁

比较典型的AQS实现类ReentrantLock,它默认就是非公平锁,新的线程与队

列中的线程共同来抢资源


二、ReentrantLock的基本概念

RenntrantLock实现了Lock接口,是一个可重入且独占式的锁。它更灵活、更强大,增加了轮询、超时、中断、公平锁和非公平锁等高级功能。


ReentrantLock主要利用CAS+AQS队列来实现。它支持公平锁和非公平锁,两者的实现类似。构造方法接受一个可选的公平参数(默认非公平锁),当设置为true时,表示公平锁,否则为非公平锁。公平锁的效率往往没有非公平锁的效率高,在许多线程访问的情况下,公平锁表现出较低的吞吐量。


ReentrantLock里面有一个内部类 sync,它 继承 AQS,添加锁和释放锁的大部分操作实际上都是在 sync中实现的。sync有公平锁fairSync和非公平锁 NonfairSync两个子类。

公平锁 : 锁被释放之后,先申请的线程先得到锁。性能较差一些,因为公平锁为了保证时间上的绝对顺序,上下文切换更频繁。

非公平锁:锁被释放之后,后申请的线程可能会先获取到锁,是随机或者按照其他优先级排序的。性能更好,但可能会导致某些线程永远无法获取到锁。


三、与Synchronized的对比

相同点:二者都是加锁方式同步,并且都是阻塞式同步。即如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的。

区别:synchronized是java语言的关键字,是原生语法层面的互斥,需要jvm实现。而ReentrantLock是jdk1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try、finally语句块来实现。


synchronized经过编译,会在同步块的前后分别形成monitorenter和monitoreExit这两个字节码指令。在执行前者指令时首先要尝试获取对象锁。如果这个锁没有被锁定,或者当前线程已经有了对象锁,就把锁的计算器加1,相应的执行后者时,将计算器减1,当计算器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞,直到对象锁被另一个线程释放为止。


ReentrantLock是java.util.concurrent包下提供的一套互斥锁,有以下高级功能:


1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于synchronized来说可以避免死锁。


2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不好。


3.锁绑定多个条件,RenntrantLock对象可以同时绑定多个对象。


相关文章
|
7月前
|
存储 程序员 编译器
C++-关键字
C++-关键字
54 1
|
存储 算法 编译器
带你了解并掌握一些C++关键字的使用
带你了解并掌握一些C++关键字的使用
102 0
|
4月前
|
C# 计算机视觉
C#中out关键字
C#中out关键字
66 0
|
7月前
|
Java
|
Java
关键字this
关键字this
69 0
单链表删除第一次关键字
删除第一次出现关键字为key的节点
|
编译器 程序员 Linux
C++关键字之likely和unlikely
C++关键字之likely和unlikely
758 0
C++关键字之likely和unlikely
|
编译器 程序员 C++
C++关键字之fallthrough
C++关键字之fallthrough
387 0
|
缓存 Java
volitile关键字
1.volatile关键字的两层语义 一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: 1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
1155 0