信号量的实现模型一般包括:1个计数器、1个等待队列、3个方法(需要保证原子性)
JDK 中 Semaphore 是基于 AbstractQueuedSynchronizer 实现,可以指定是否公平
信号量 Semaphore 实现的伪代码:
class Semaphore{
//计数器
int count;
//等待队列
Queue queue;
//初始化
Semaphore(int c){
this.count=c;
}
//获取许可证
void acquire(){
count--;
if(count<0){
//将当前线程插入等待队列
//阻塞当前线程
}
}
//获取许可证
void release(){
count++;
if(count<=0) {
//移除等待队列中的某个线程
//唤醒某个线程
}
}
}
使用信号量实现互斥锁效果:
package constxiong.interview;
import java.util.concurrent.Semaphore;
/**
* 测试使用信号量实现锁的效果
* @author ConstXiong
* @date 2019-12-18 14:18:47
*/
public class TestSemaphore {
private static int count;
private static Semaphore semaphore = new Semaphore(1);
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
add();
System.out.println(count);
}).start();
}
}
private static void add() {
try {
semaphore.acquire();
Thread.sleep(100);
count++;
} catch(InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
}
除了能实现互斥锁,信号量还可以做到允许多个线程访问同一个临界区,这是它与互斥锁一个较大的区别点。
将代码进行修改,实现限流功能:
package constxiong.interview;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 测试使用信号量实现限流的效果
* @author ConstXiong
* @date 2019-12-18 14:18:47
*/
public class TestSemaphore {
private static AtomicInteger acount = new AtomicInteger(0);
private static Semaphore semaphore = new Semaphore(10);
public static void main(String[] args) {
testAddAtomic();
}
/**
* 测试允许十个线程并发递增 acount
*/
private static void testAddAtomic() {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(addAtomic());
}).start();
}
}
private static int addAtomic() {
try {
semaphore.acquire();
Thread.sleep(100);
return acount.incrementAndGet();
} catch(InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
return -1;
}
}
在实际的 Java 开发中,信号量的使用相对互斥锁来说较少,知名度没那么高,但在其他编程语言中使用较广。
ConstXiong 备案号:苏ICP备16009629号-3