JUC中的Semaphore(信号量)-限流

synchronized和重入锁ReentrantLock,这2种锁一次都只能允许一个线程访问一个资源,而信号量可以控制有多少个线程可以访问特定的资源
Semaphore常用场景:限流

看过一个大佬写过的例子:

比如有个停车场,有5个空位,门口有个门卫,手中5把钥匙分别对应5个车位上面的锁,来一辆车,门卫会给司机一把钥匙,然后进去找到对应的车位停下来,出去的时候司机将钥匙归还给门卫。停车场生意比较好,同时来了100两车,门卫手中只有5把钥匙,同时只能放5辆车进入,其他车只能等待,等有人将钥匙归还给门卫之后,才能让其他车辆进入。

上面的例子中门卫就相当于Semaphore,车钥匙就相当于许可证,车就相当于线程

Semaphore主要方法

Semaphore(int permits):构造方法,参数表示许可证数量,用来创建信号量

Semaphore(int permits,boolean fair):构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量

void acquire() throws InterruptedException:从此信号量获取1个许可前线程将一直阻塞,相当于一辆车占了一个车位,此方法会响应线程中断,表示调用线程的interrupt方法,会使该方法抛出InterruptedException异常

void acquire(int permits) throws InterruptedException :和acquire()方法类似,参数表示需要获取许可的数量;比如一个大卡车要入停车场,由于车比较大,需要申请3个车位才可以停放

void acquireUninterruptibly(int permits) :和acquire(int permits) 方法类似,只是不会响应线程中断

boolean tryAcquire():尝试获取1个许可,不管是否能够获取成功,都立即返回,true表示获取成功,false表示获取失败

boolean tryAcquire(int permits):和tryAcquire(),表示尝试获取permits个许可

boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException:尝试在指定的时间内获取1个许可,获取成功返回true,指定的时间过后还是无法获取许可,返回false

boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException:和tryAcquire(long timeout, TimeUnit unit)类似,多了一个permits参数,表示尝试获取permits个许可

void release():释放一个许可,将其返回给信号量,相当于车从停车场出去时将钥匙归还给门卫

void release(int n):释放n个许可

int availablePermits():当前可用的许可数

举例,设置许可数为2.打印线程获取许可过程
acquire()

package com.example.demo.demo.conditionLockDemo;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * SemaPhore信息量:常用场景:限流
 *synchronized和重入锁ReentrantLock,这2种锁一次都只能允许一个线程访问一个资源,而信号量可以控制有多少个线程可以访问特定的资源。
 */
public class SemaPhoreDemo {
   static Semaphore semaphore = new Semaphore(2);//参数表示许可证数量,用来创建信号量

    public static class T extends Thread{
        @Override
        public void run() {
            try {
                semaphore.acquire();//获取许可
                System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"获取许可");
                TimeUnit.SECONDS.sleep(2);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            finally {
                semaphore.release();
                System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"释放许可");
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i <10 ; i++) {
            T t = new T();
            t.setName("t"+i);
            t.start();
        }
    }
}

结果

1590980975333:t0获取许可
1590980975333:t1获取许可
1590980977334:t1释放许可
1590980977334:t2获取许可
1590980977334:t0释放许可
1590980977334:t3获取许可
1590980979334:t3释放许可
1590980979334:t2释放许可
1590980979334:t5获取许可
1590980979334:t4获取许可
1590980981334:t4释放许可
1590980981334:t6获取许可
1590980981334:t7获取许可
1590980981334:t5释放许可
1590980983335:t6释放许可
1590980983335:t8获取许可
1590980983335:t9获取许可
1590980983335:t7释放许可
1590980985335:t9释放许可
1590980985335:t8释放许可

结果t0和t1获取到许可,2秒后t1释放许可,t2才能获取到,只要当存在可用许可数时,线程才能获取并访问

规定的时间内希望获取许可

package com.example.demo.demo.conditionLockDemo;

import java.sql.Time;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * Semaphore中定时获取许可
 */
public class SemaphoreDemo2 {
    static Semaphore semaphore = new Semaphore(1);
    public static class T extends  Thread{
        @Override
        public void run() {
            Boolean acquireSuccess = false;//获取许可是否成功
            try {
                //1秒尝试获取许可,获取成功返回true,失败false
                System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"尝试获取许可,当前可用许可数量"+semaphore.availablePermits());
                acquireSuccess = semaphore.tryAcquire(1, TimeUnit.SECONDS);
                if(acquireSuccess){
                    System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"成功获取许可,当前可用许可数量"+semaphore.availablePermits());
                    TimeUnit.SECONDS.sleep(5);
                }else {
                    System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"获取许可失败,当前可用许可数量"+semaphore.availablePermits());
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            finally {
                if (acquireSuccess){
                    semaphore.release();
                    System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"成功释放许可,当前可用许可数量"+semaphore.availablePermits());
                }
            }
        }

        public static void main(String[] args) throws InterruptedException {
            T t1 = new T();
            t1.setName("t1");
            T t2 = new T();
            t2.setName("t2");
            T t3 = new T();
            t3.setName("t3");
            t1.start();
            TimeUnit.SECONDS.sleep(1);
            t2.start();
            TimeUnit.SECONDS.sleep(1);
            t3.start();
        }
    }
}

1590981406919:t1尝试获取许可,当前可用许可数量1
1590981406921:t1成功获取许可,当前可用许可数量0
1590981407918:t2尝试获取许可,当前可用许可数量0
1590981408919:t2获取许可失败,当前可用许可数量0
1590981408919:t3尝试获取许可,当前可用许可数量0
1590981409921:t3获取许可失败,当前可用许可数量0
1590981411921:t1成功释放许可,当前可用许可数量1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值