《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!
-
- 前言
-
代码示例
-
Semaphore基本结构
-
获取资源许可
-
- tryAcquireShared
-
- Semaphore.NonfairSync#tryAcquireShared
-
Semaphore.FairSync#tryAcquireShared
-
释放资源许可
-
- Semaphore.Sync#tryReleaseShared
-
资源许可清零Semaphore#drainPermits
-
总结
Semaphore翻译是信号量的意思,可以控制并发访问资源的数量。
Semaphore semaphore = new Semaphore(10); //初始化一个信号桶,也可以叫令牌桶,里面有10个资源许可
semaphore.acquire();//获取一个资源许可
semaphore.release();//释放一个资源许可
10个资源许可被取完后,再来线程获取就会入队列阻塞。
Semaphore
是在AQS
基础上实现的共享锁,获取资源和释放资源都是调用的AQS中共享锁模板方法,故只需要看tryAcquireShared
和tryReleaseShared
在Semaphore
中的实现。
首先初始化Semaphore,给资源许可5个,模拟多个线程获取资源。
public class Test1072 {
private static Semaphore semaphore = new Semaphore(5);
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new MyThread(i));
thread.start();
}
}
static class MyThread implements Runnable{
private int i;
public MyThread(int i) {
this.i = i;
}
@Override
public void run() {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + “, semaphore.acquire()获取资源–” + i);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// System.out.println(Thread.currentThread().getName() + “,semaphore.release()释放资源–” + i);
// semaphore.release();
}
}
}
}
//控制台输出
//线程只获取资源不释放
Thread-0, semaphore.acquire()获取资源–0
Thread-1, semaphore.acquire()获取资源–1
Thread-2, semaphore.acquire()获取资源–2
Thread-6, semaphore.acquire()获取资源–6
Thread-3, semaphore.acquire()获取资源–3
//线程获取资源并释放资源
Thread-0, semaphore.acquire()获取资源–0
Thread-2, semaphore.acquire()获取资源–2
Thread-2,semaphore.release()释放资源–2
Thread-1, semaphore.acquire()获取资源–1
Thread-1,semaphore.release()释放资源–1
Thread-0,semaphore.release()释放资源–0
Thread-3, semaphore.acquire()获取资源–3
Thread-3,semaphore.release()释放资源–3
Thread-5, semaphore.acquire()获取资源–5
Thread-5,semaphore.release()释放资源–5
Thread-4, semaphore.acquire()获取资源–4
Thread-4,semaphore.release()释放资源–4
Thread-6, semaphore.acquire()获取资源–6
Thread-6,semaphore.release()释放资源–6
Thread-7, semaphore.acquire()获取资源–7
Thread-7,semaphore.release()释放资源–7
Thread-9, semaphore.acquire()获取资源–9
Thread-9,semaphore.release()释放资源–9
Thread-8, semaphore.acquire()获取资源–8
Thread-8,semaphore.release()释放资源–8
在没有释放资源前,只有五个线程可以获取资源,其他线程都进入队列阻塞。当线程获取资源,执行完业务代码释放资源,则每个线程都可以获取资源,无需阻塞。
Semaphore
中也有一个内部类Sync
,Sync
继承自AbstractQueuedSynchronizer
,所以核心代码都在Sync
中。从构造函数看出,Sync
还有两个子类NonfairSync
和FairSync
,说明Semaphore
实现的共享锁区分公平性。
public class Semaphore implements java.io.Serializable {
private static final long serialVersionUID = -3222578661600680210L;
/** All mechanics via AbstractQueuedSynchronizer subclass */
private final Sync sync;
/**
-
Synchronization implementation for semaphore. Uses AQS state
-
to represent permits. Subclassed into fair and nonfair
-
versions.
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
… …
}
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
}
Semaphore提供了可中断获取资源许可(Semaphore#acquire()
),不可中断获取资源许可(Semaphore#acquireUninterruptibly()
),尝试获取资源许可(Semaphore#tryAcquire()
),超时可中断获取资源许可(Semaphore#tryAcquire(long, java.util.concurrent.TimeUnit)
)。底层代码调用的都是AQS中共享模式获取锁的模板方法,故只需要看看tryAcquireShared
在Semaphore
中的实现。
//1.可中断获取资源许可
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
//2.可中断获取permits个资源许可
public void acquire(int permits) throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);
}
//3.不可中断获取资源许可
public void acquireUninterruptibly() {
sync.acquireShared(1);
}
//4.不可中断获取permits个资源许可
public void acquireUninterruptibly(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireShared(permits);
}
//5.尝试获取资源许可,获取成功返回true
public boolean tryAcquire() {
return sync.nonfairTryAcquireShared(1) >= 0;
}
//6.尝试获取permits个资源许可,获取成功返回true
public boolean tryAcquire(int permits) {
if (permits < 0) throw new IllegalArgumentException();
return sync.nonfairTryAcquireShared(permits) >= 0;
}
//7.超时可中断获取资源许可,获取失败进入队列阻塞一段时间,超时还未获取返回false
public boolean tryAcquire(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
//8.超时可中断获取permits个资源许可,获取失败进入队列阻塞一段时间,超时还未获取返回false
public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
}
tryAcquireShared
Semaphore中获取资源许可有公平锁和非公平锁之分。
Semaphore.NonfairSync#tryAcquireShared
NonfairSync
中的tryAcquireShared
调用了Semaphore.Sync
中已经实现好的nonfairTryAcquireShared
。
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -2694183684443567898L;
NonfairSync(int permits) {
super(permits);
}
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
}
获取资源许可,就是对state做减法,remaining =当前许可量—获取的许可量,remaining >= 0
即可以CAS
修改state
资源许可数,获取成功返回remaining
资源许可剩余量。CAS
修改state失败会不断自旋。
//java.util.concurrent.Semaphore.Sync#nonfairTryAcquireShared
final int nonfairTryAcquireShared(int acquires) {
for (;😉 {
//获取可用资源许可量
int available = getState();
//计算可用资源许可剩余量
int remaining = available - acquires;
//remaining <0 说明资源许可耗尽
//remaining >= 0 可继续获取资源许可cas
if (remaining < 0 ||
compareAndSetState(available, remaining))
//返回剩余许可量
return remaining;
}
}
写在最后
很多人感叹“学习无用”,实际上之所以产生无用论,是因为自己想要的与自己所学的匹配不上,这也就意味着自己学得远远不够。无论是学习还是工作,都应该有主动性,所以如果拥有大厂梦,那么就要自己努力去实现它。
最后祝愿各位身体健康,顺利拿到心仪的offer!
由于文章的篇幅有限,所以这次的蚂蚁金服和京东面试题答案整理在了PDF文档里
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!
ining;
}
}
写在最后
很多人感叹“学习无用”,实际上之所以产生无用论,是因为自己想要的与自己所学的匹配不上,这也就意味着自己学得远远不够。无论是学习还是工作,都应该有主动性,所以如果拥有大厂梦,那么就要自己努力去实现它。
最后祝愿各位身体健康,顺利拿到心仪的offer!
由于文章的篇幅有限,所以这次的蚂蚁金服和京东面试题答案整理在了PDF文档里
[外链图片转存中…(img-Jbe5RFps-1714467456083)]
[外链图片转存中…(img-Ay9OQKia-1714467456083)]
[外链图片转存中…(img-0OVlNLpa-1714467456084)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!