基本介绍
多线程中上锁的目的一般是一种对受限资源的保护,例如:保证同一时刻只有一个线程能访问的ReentrantLock
,或者保证只有一个线程可以写入的ReadWriteLock
还有一种受限资源,它需要保证同一时刻最多有N个线程能访问,比如同一时刻最多创建100个数据库连接,最多允许10个用户下载等
这种限制数量的锁,如果用Lock数组来实现,就太麻烦了。
这种情况就可以使用Semaphore
,例如,最多允许2个线程同时访问:
代码测试
public class TestSemaphore {
public static void main(String[] args) throws InterruptedException {
AccessLimitControl control = new AccessLimitControl();
List<Thread> tList = new ArrayList<>();
for (int i = 0; i< 5; i++) {
Thread t = new Thread(() -> {
try {
String access = control.access();
System.out.println("线程:" + Thread.currentThread().getName() + " 的返回值:" + access);
} catch (Exception e) {
e.printStackTrace();
}
});
tList.add(t);
}
for (Thread thread : tList) {
thread.start();
}
for (Thread thread : tList) {
thread.join();
}
}
static class AccessLimitControl {
// 任意时刻仅允许最多3个线程获取许可:
final Semaphore semaphore = new Semaphore(1);
public String access() throws Exception {
// 如果超过了许可数量,其他线程将在此等待:
System.out.println("进入队列的线程:" + Thread.currentThread().getName());
semaphore.acquire();
System.out.println("当前线程名称:" + Thread.currentThread().getName());
try {
Thread.sleep(2000);
return UUID.randomUUID().toString();
} finally {
semaphore.release();
}
}
}
}
代码运行,以下看似 Thread-3
和 Thread-1
同时进入,其实是 Thread-3
return 后打印结果时,Thread-1
立刻进入了
进入队列的线程:Thread-3
进入队列的线程:Thread-4
进入队列的线程:Thread-1
进入队列的线程:Thread-2
进入队列的线程:Thread-0
当前线程名称:Thread-3
当前线程名称:Thread-1
线程:Thread-3 的返回值:997edc5d-7ec4-4160-a3b7-0d4a76fbb2ff
线程:Thread-1 的返回值:ba87b784-66d0-4073-9967-ccf44df4214a
当前线程名称:Thread-2
线程:Thread-2 的返回值:5c784f8c-fef9-4fa8-83cc-98ee2e7e6238
当前线程名称:Thread-4
线程:Thread-4 的返回值:376938f5-98ab-49da-9402-566523f31ed0
当前线程名称:Thread-0
线程:Thread-0 的返回值:f51391af-649a-404a-a2d7-68b073d44ec0
小结
Semaphore
本质上就是一个信号计数器,用于限制同一时间的最大访问数量,如果要对某一受限资源进行限流访问,可以使用Semaphore
,保证同一时间最多N个线程访问受限资源。