当前位置:网站首页>【juc学习之路第7天】ReentrantLock与ReentrantReadWriteLock
【juc学习之路第7天】ReentrantLock与ReentrantReadWriteLock
2022-06-11 23:51:00 【birdyson】
线程锁
位于jucl下,主要有两种接口类型的锁:
Lock:包含以下三种形式锁的类型:
- 公平锁:不同的线程获取锁的过程是公平的
- 非公平锁:不同线程获取锁的过程是不公平的,允许竞争获取。
- 可重入锁:同一个锁可以被一个线程多次获取,避免死锁的出现。
ReadWhiteLock: 提供读锁和写锁,读时锁共享,修改时独占。
ReentrantLock
互斥锁或叫独占锁,是Lock的实现类,意思是一旦获取到锁之后,其他线程不允许再操作(无论读或写),synchronized也是互斥锁。
先观察下ReentrantLock的源码:
package java.util.concurrent.locks;
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
}
继续扒Sync:
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
}
继续扒AbstractQueuedSynchronizer:(这就是JUC另一核心:AQS)
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer implements java.io.Serializable {
private static final long serialVersionUID = 7373984972572414691L;
}
继续:
public abstract class AbstractOwnableSynchronizer
implements java.io.Serializable {
AQS 的本质是一个执行队列,所有的待执行线程全部都保存在一个队列之中,可以解决死锁问题。在JUC的AQS里面提供了一个CLH队列。CLH (Craig, Landin, and Hagersten)锁是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现前驱释放了锁就结束自旋。
/** JDK17 CLH Nodes */
abstract static class Node {
volatile Node prev; // initially attached via casTail
volatile Node next; // visibly nonnull when signallable
Thread waiter; // visibly nonnull when enqueued
volatile int status; // written by owner, atomic bit ops by others
}
获取锁的机制是由AQS的子类Sync提供的,Sync也有两个子类:FairSync、NonfairSync。
ReentrantLock在操作时有两种情况:
- 多个线程抢占互斥锁资源:

- 互斥锁抢夺与等待:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fShBnwgJ-1653492592222)(/Users/alexanderron/Library/Application Support/typora-user-images/image-20220525103823265.png)]](/img/44/0ba7f06287734179ee66b8f4990910.png)
等待的线程会保存在AQS中的CLH等待队列中,锁竞争的机制是由Sync决定的,可以发现默认是非公平锁,是比公平锁更有效率,也是更能发挥出计算机的性能。
private final Sync sync;
public ReentrantLock() {
sync = new NonfairSync();}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();}
lock()与unlock()
public void lock() {
// 此处简写
sync.acquire(1);
}
public void unlock() {
sync.release(1);
}
在进行线程锁定的过程之中是依靠线程锁定数量的控制,锁定的时候都会调用锁定计数的方法:acquire(1),每当一个线程被锁定了,这个时候计数就会+1,CLH就依靠锁定数量是否为0来确定是否有锁定的线程,从而解决线程死锁问题。在每一次解锁的时候会调用release(1)释放一个锁定。
设计一个抢票系统
class SaleSystem {
private int ticket;
private static final ReentrantLock LOCK = new ReentrantLock();
public SaleSystem() {
}
public SaleSystem(int ticket) {
this.ticket = ticket;
}
public void sale() {
LOCK.lock();
try {
if (this.ticket > 0) {
System.out.printf("【%s】售票成功!剩余票数:%d\n",
Thread.currentThread().getName(), this.ticket --);
} else {
System.out.printf("【%s】没有票啦!\n", Thread.currentThread().getName());
}
}catch (Exception e) {
e.printStackTrace();
} finally {
LOCK.unlock();
}
}
}
public class Main {
public static void main(String[] args) throws Exception {
SaleSystem saleSystem = new SaleSystem(5);
for (int i = 0; i < 8; i ++) {
new Thread(saleSystem::sale).start();
}
}
}
【Thread-0】售票成功!剩余票数:5
【Thread-4】售票成功!剩余票数:4
【Thread-1】售票成功!剩余票数:3
【Thread-3】售票成功!剩余票数:2
【Thread-5】售票成功!剩余票数:1
【Thread-2】没有票啦!
【Thread-6】没有票啦!
【Thread-7】没有票啦!
ReentrantReadWriteLock
非独占锁,读锁属于共享锁,所有的读线程共享一个共享锁,当写锁工作的时候,整个共享锁将进入到暂停阶段,等待写完成后再进行多个并发并发读取。


public class ReentrantReadWriteLock
implements ReadWriteLock, java.io.Serializable {
private static final long serialVersionUID = -6992448646407690164L;
private final ReentrantReadWriteLock.ReadLock readerLock;
private final ReentrantReadWriteLock.WriteLock writerLock;
final Sync sync;
public ReentrantReadWriteLock() {
this(false);
}
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
public ReentrantReadWriteLock.WriteLock writeLock() {
return writerLock; }
public ReentrantReadWriteLock.ReadLock readLock() {
return readerLock; }
}
边栏推荐
- Read the logstash principle
- Are you still struggling with the gold content of PMP
- EFCore中数据表的两种配置方式
- 【JUC系列】Executor框架之概览
- 愉快无负担的跨进程通信方式
- Graph and graph traversal
- 预解析与作用域
- PHP mkdir(): permission denied uploading a file will change the folder permission to 411 permission
- sonarqube介绍和安装步骤
- (dp) acwing 899. Edit distance
猜你喜欢
![[signals and systems] (XXII) Laplace transform and complex frequency domain analysis - s-domain analysis](/img/35/a23646ac8501ac646cd44eeecd5b79.jpg)
[signals and systems] (XXII) Laplace transform and complex frequency domain analysis - s-domain analysis

Introduction and installation steps of sonarqube

2022 low voltage electrician certificate and online simulation examination

Anaconda download package error: valueerror: check_ hostname requires server_ hostname

Teach you to play with SSM framework

Chisel environment setup (win10 + vscode)

HMS core shows the latest open capabilities in mwc2022, helping developers build high-quality applications

Solr之基礎講解入門

chisel环境搭建(win10 + vscode)

(simple statistics) acwing 3404 Who are your potential friends
随机推荐
Single page pull-down refresh and double page pull-down refresh of MUI
Jenkins basic configuration
自定义JSP标签->概念->生命周期
Lake Shore—SuperVariTemp 低温恒温器
Wechat applet Bluetooth development
(simple statistics) acwing 3404 Who are your potential friends
Vs code writing assembly code [microcomputer principle]
Handwritten simple promise
(dp) acwing 899. Edit distance
Share a treasure website necessary for new media operation for free
Balanced binary tree (AVL tree)
Stack (C language)
Solr之基礎講解入門
[signals and systems] (XXII) Laplace transform and complex frequency domain analysis - s-domain analysis
唤醒手腕 - 神经网络与深度学习(Tensorflow应用)更新中
[C language] data type storage, original code, inverse code and complement code
2022 high place installation, maintenance and removal of simulated examination platform for operation certificate examination question bank
mysql——find_ in_ Set usage
Jetpack architecture component learning (3) -- activity results API usage
CVPR 2022 | meta learning performance in image regression task