Java中的信号量Semaphore

信号量的实现模型一般包括:1个计数器、1个等待队列、3个方法(需要保证原子性)

Semaphore 实现的伪代码(JDK 中 Semaphore 是基于 AbstractQueuedSynchronizer 实现,可以指定是否公平):

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 开发中,信号量的使用相对互斥锁来说较少,知名度没那么高,但在其他编程语言中使用较广。


原文链接
 


 

原文地址:https://www.cnblogs.com/ConstXiong/p/12065843.html