Java面试必问题目:AQS原理深度剖析,看完吊打面试官!

更新时间:2023-06-14 03:09:02 阅读: 评论:0

Java⾯试必问题⽬:AQS原理深度剖析,看完吊打⾯试官!
⼤家好,我是⼩马哥。最近并发编程是⼤⼚⾯试中重点考察的问题。今天我们来探讨⼀下AQS相关的⾯试技巧。毕竟此类问题回答的好坏会在很⼤程度上影响我们⾯试的得分。
1. AQS在java中的使⽤
给代码加锁,是java中处理并发问题的重要⼿段。
java中的很多锁都是基于抽象类AQS(AbstractQueuedSynchronizer)实现的。
如下表所⽰:
2. AQS的实现机制
AQS提供了实现锁的机制,即CLH队列,同时通过ConditionObject实现了条件等待链表。
其中CLH队列如下:
1. AQS使⽤ private volatile int state; 表⽰同步状态
2. 通过内置的FIFO队列完成线程的排队
3. 使⽤CAS对state进⾏修改。
3. AQS主要⽅法
AQS对外提供的⽤于实现锁的⽅法如下:
基于AQS可以实现公平锁和⾮公平锁,互斥锁和共享锁。
4. ReentrantReadWriteLock
ReentrantReadWriteLock中的写锁实现了互斥锁,读锁实现了共享锁。
上课容易走神是什么原因其中写锁的互斥性,⽤于保证不会并发执⾏写操作,保证了数据的⼀致性。
其中读锁的共享性,确保可以多线程同时读取,提升了读的优先级,对于读操作执⾏逻辑较重的场合,⽐较合适。
在抢锁的时候,只有⼀个写线程可以抢锁成功,但同时可能有多个读线程抢锁成功,由于读写互斥,容易引起读线程“饿死”的情况。
4.1. 互斥锁
写线程通过调⽤WriteLock的lock⽅法来获取互斥锁。
urrent.locks.ReentrantReadWriteLock.WriteLock#lock
public void lock() {
sync.acquire(1);
}
中小型犬品种大全
urrent.locks.AbstractQueuedSynchronizer#acquire
该⽅法⾸先尝试获取锁,如果获取失败,就将当前线程封装为Node对象,追加到CLH队列中,休眠,等待抢锁。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
lfInterrupt();
}
之所以称为互斥锁,是因为该⽅法向CLH队列添加的节点是单个节点,只封装了⼀个线程。
关于互斥锁的获取流程,感兴趣的⼩伙伴可以加微信 Geanmingti 索取。
4.2. 共享锁
读操作通过调⽤读写锁ReadLock的lock来获取共享锁。
urrent.locks.ReentrantReadWriteLock.ReadLock#lock
public void lock() {
sync.acquireShared(1);
}
urrent.locks.AbstractQueuedSynchronizer#acquireShared
该⽅法⾸先尝试获取共享锁,如果抢锁失败,则执⾏线程节点⼊CLH队列的操作。
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
之所以称为共享锁,是因为在该⽅法中,会判断CLH队列尾节点是互斥操作还是共享操作,如果是互斥操作,则当前线程节点追加到尾节点后⾯;如果是共享操作,则通过引⽤,挂到尾节点的横向链表上,当获取锁的时候,横向链表中的节点线程⼀并获取到锁。
关于共享锁的获取流程,感兴趣的⼩伙伴可以加微信 Geanmingti 索取。
涅盘重生的励志句子5. ReentrantLock
ReentrantLock实现了公平锁和⾮公平锁。
5.1. 抢锁操作
urrent.locks.ReentrantLock#lock
该⽅法⽤于获取互斥锁。
public void lock() {
双子狮子sync.acquire(1);
}
urrent.locks.AbstractQueuedSynchronizer#acquire
上述⽅法调⽤了AQS的acquire⽅法,⽤于获取锁,该⽅法⾸先尝试获取锁,如果获取锁失败,就将当前线程封装为Node接待,追加到CLH队列中。
public final void acquire(int arg) {
小米鸡蛋粥if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
lfInterrupt();
}
上述⽅法中的tryAcquire⽅法,该⽅法调⽤了ReentrantLock内部类Sync的实现。
Sync类有两个⼦类,分别是FairSync和NofairSync。其中FairSync实现了公平锁功能,NonfairSync实现了⾮公平锁的功能。
5.2. 公平锁
当前线程在抢锁的时候,先判断CLH队列中有没有其他线程在等待获取锁,如果没有,再去抢锁。如果有,则乖乖排队:
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 如果没有前置节点等待抢锁,才去抢
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
tExclusiveOwnerThread(current);
return true;
}
}
// ......
桌面小便签关于公平锁的获取流程,感兴趣的⼩伙伴可以加微信 Geanmingti 索取。
5.3. ⾮公平锁
tryAcquire⽅法的实现如下,该⽅法调⽤了nonfairTryAcquire⽅法⽤于实现⾮公平抢锁。
urrent.locks.ReentrantLock.NonfairSync#tryAcquire
protected final boolean tryAcquire(int acquires) {
// ⾮公平尝试获取锁
return nonfairTryAcquire(acquires);
}我为你受冷风吹
下⾯⽅法中,表⽰没有线程持有锁,不管是否有线程在等待,直接抢,⾮公平。
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
tExclusiveOwnerThread(current);
return true;
}
}
// ......
无锡小笼包
关于⾮公平锁的获取流程,感兴趣的⼩伙伴可以加微信 yuer900411_sky 索取。
关于如何学习Java,⼀⽅⾯需要不断的去学习,把基础知识学扎实,另⼀⽅⾯也要认识到java的学习不能仅仅靠理论,更多的是靠实操,所以要多练习多做项⽬,在实践中学习才是最好的学习⽅法。很多⼈刚开始不知道怎么去学习,那么我这⾥有⼀套Java2021最新1000道⾯试pdf总结,不怕⾯试被问到,私我获取哦

本文发布于:2023-06-14 03:09:02,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1037473.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:线程   获取   学习   节点
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图