Java Semaphore详解

1、介绍

Semaphore(信号量)是用来控制同时访问特定资源的线程数量,通过协调各个线程以保证合理地使用公共资源。

Semaphore通过使用计数器来控制对共享资源的访问。 如果计数器大于0,则允许访问。 如果为0,则拒绝访问。 计数器所计数的是允许访问共享资源的许可。 因此,要访问资源,必须从信号量中授予线程许可。

2、主要方法

  • void acquire() :从信号量获取一个许可,如果无可用许可前将一直阻塞等待,

  • void acquire(int permits) :获取指定数目的许可,如果无可用许可前也将会一直阻塞等待

  • boolean tryAcquire():从信号量尝试获取一个许可,如果无可用许可,直接返回false,不会阻塞

  • boolean tryAcquire(int permits): 尝试获取指定数目的许可,如果无可用许可直接返回false

  • boolean tryAcquire(int permits, long timeout, TimeUnit unit)
    在指定的时间内尝试从信号量中获取许可,如果在指定的时间内获取成功,返回true,否则返回false

  • void release():释放一个许可,别忘了在finally中使用,注意:多次调用该方法,会使信号量的许可数增加,达到动态扩展的效果,如:初始permits为1,调用了两次release,最大许可会改变为2

  • int availablePermits(): 获取当前信号量可用的许可

Semaphore构造函数

 public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }
  • permits 初始许可数,也就是最大访问线程数
  • fair 当设置为false时,创建的信号量为非公平锁;当设置为true时,信号量是公平锁

关于java非公平锁和公平锁可以看这篇文章:一文搞懂java中的锁

3、Semaphore登录限流示例

在以下示例中,实现一个简单的登录队列,通过Semaphore来限制系统中的用户数:

public static void main(String[] args) {

        //允许最大的登录数
        int slots=10;
        ExecutorService executorService = Executors.newFixedThreadPool(slots);
        LoginQueueUsingSemaphore loginQueue = new LoginQueueUsingSemaphore(slots);
        //线程池模拟登录
        for (int i = 1; i <= slots; i++) {
            final int num=i;
            executorService.execute(()->{
                 if (loginQueue.tryLogin()){
                     System.out.println("用户:"+num+"登录成功!");
                 }else {
                     System.out.println("用户:"+num+"登录失败!");
                 }
            });
        }
        executorService.shutdown();


        System.out.println("当前可用许可证数:"+loginQueue.availableSlots());

        //此时已经登录了10个用户,再次登录的时候会返回false
        if (loginQueue.tryLogin()){
            System.out.println("登录成功!");
        }else {
            System.out.println("系统登录用户已满,登录失败!");
        }
        //有用户退出登录
        loginQueue.logout();

        //再次登录
        if (loginQueue.tryLogin()){
            System.out.println("登录成功!");
        }else {
            System.out.println("系统登录用户已满,登录失败!");
        }

    }
class LoginQueueUsingSemaphore{

    private Semaphore semaphore;

    /**
     *
     * @param slotLimit
     */
    public LoginQueueUsingSemaphore(int slotLimit){
        semaphore=new Semaphore(slotLimit);
    }

    boolean tryLogin() {
        //获取一个凭证
        return semaphore.tryAcquire();
    }

    void logout() {
        semaphore.release();
    }

    int availableSlots() {
        return semaphore.availablePermits();
    }
}

运行结果:
在这里插入图片描述

  • 10
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

warybee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值