Semaphore是什么?

Semaphore简介

semaphore英文翻译为信号标,它是能控制允许多少线程去访问资源,也可以反馈线程在指定时间是否获得可执行权的信号,从而对这些超时未获取权力的线程做另行安排。

Semaphore使用场景

从简介中可以得知,semaphore可以限制并发访问数量,即为限流,像是微服务组件hystrix、sentinel等限流中间件都可使用此原理,当然随之而来,那些被限制通行的线程是被丢弃?还是去执行另外的流程,就是“降级服务”。

Semaphore使用demo

1、定义线程任务+降级服务

@Slf4j
public class DegradeTask extends Thread{
    Semaphore semaphore;
    public DegradeTask(Semaphore semaphore,String tname){
        super(tname);
        this.semaphore=semaphore;
    }
    public void run(){
        try {
            //tryAcquire尝试在500毫秒内获取执行权,并返回true/false反馈是否成功
            boolean b = semaphore.tryAcquire(500, TimeUnit.MILLISECONDS);
            //获取成功
            if(b){
                //执行任务
                log.info("{}线程在{}时间执行任务",Thread.currentThread().getName(),System.currentTimeMillis());
                Thread.sleep(200);
                //执行完任务需要释放权利,以供其他线程拿到执行权
                semaphore.release();
            //获取失败
            }else{
                //执行降级任务
                degrade();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 定义降级任务
     */
    private void degrade(){
        log.info("降级服务");
    }

}

2、模拟线程并发测试结果

public class TestMyTask {
    public static void main(String[] args) {
        //初始值为几?(就是限制几个线程同时执行,并行)
        Semaphore semaphore = new Semaphore(3);
        //模拟20个线程去抢执行权
        for (int i = 0; i < 20; i++) {
            new Thread(new DegradeTask(semaphore,"线程"+i)).start();
        }
    }
}

测试结果

[Thread-2] INFO testSemaphore.DegradeTask - Thread-2线程在1625380595501时间执行任务
[Thread-1] INFO testSemaphore.DegradeTask - Thread-1线程在1625380595501时间执行任务
[Thread-0] INFO testSemaphore.DegradeTask - Thread-0线程在1625380595501时间执行任务
[Thread-4] INFO testSemaphore.DegradeTask - Thread-4线程在1625380595709时间执行任务
[Thread-5] INFO testSemaphore.DegradeTask - Thread-5线程在1625380595709时间执行任务
[Thread-3] INFO testSemaphore.DegradeTask - Thread-3线程在1625380595709时间执行任务
[Thread-6] INFO testSemaphore.DegradeTask - Thread-6线程在1625380595910时间执行任务
[Thread-8] INFO testSemaphore.DegradeTask - Thread-8线程在1625380595910时间执行任务
[Thread-7] INFO testSemaphore.DegradeTask - Thread-7线程在1625380595910时间执行任务
[Thread-9] INFO testSemaphore.DegradeTask - 降级服务
[Thread-10] INFO testSemaphore.DegradeTask - 降级服务
[Thread-17] INFO testSemaphore.DegradeTask - 降级服务
[Thread-13] INFO testSemaphore.DegradeTask - 降级服务
[Thread-18] INFO testSemaphore.DegradeTask - 降级服务
[Thread-16] INFO testSemaphore.DegradeTask - 降级服务
[Thread-15] INFO testSemaphore.DegradeTask - 降级服务
[Thread-14] INFO testSemaphore.DegradeTask - 降级服务
[Thread-12] INFO testSemaphore.DegradeTask - 降级服务
[Thread-11] INFO testSemaphore.DegradeTask - 降级服务
[Thread-19] INFO testSemaphore.DegradeTask - 降级服务

semaphore源码解析

  • 每个线程必须从semaphore获得一个许可,当线程执行完后,许可将被返回到池中,并向semaphore返回一个许可,允许另一个线程获得该许可。
  • 请注意,在调用semaphore的acquire时不会持有同步锁,因为这将阻止将许可返回到池中。semaphore封装了限制对池的访问所需的同步,与维护池本身一致性所需的任何同步是分开的。
  • 一个初始化为1的semaphore,它最多只有一个可用的许可,就可以作为一个互斥锁。这通常被称为二进制信号量,因为它只有两种状态:一种允许可用,或者不允许。当以这种方式使用时,二进制信号量具有一个属性(不像许多java.util.concurrent.lock Lock实现),即“锁”可以由除所有者以外的线程释放(因为信号量没有所有权的概念)。这在某些特定的上下文中可能很有用,比如死锁恢复。
  • 这个类的构造函数可选地接受公平性参数。
    • 当设置为false时,该类不保证线程获取许可的顺序。特别地,是允许阻塞的,也就是说,一个调用acquire的线程可以在一个正在等待的线程之前被分配一个许可证——逻辑上,新线程将自己放在等待线程队列的头部。
    • 当公平性设置为true时,信号量保证调用任何获取方法的线程会被选择,以其调用这些方法的顺序获得许可(先入先出;先进先出)。请注意,FIFO顺序必然适用于这些方法中特定的内部执行点。因此,一个线程可能在另一个线程之前调用acquire,但在另一个线程之后到达排序点,从方法返回时也是如此。还要注意,非定时的tryAcquire方法不遵守公平性设置,但会接受任何可用的许可。
    • 通常,用于控制资源访问的信号量应该初始化为公平的,以确保没有线程因为访问资源而耗尽。当将信号量用于其他类型的同步控制时,非公平排序的吞吐量优势往往超过公平性考虑。
  • 该类还提供了方便的方法来一次获取和释放多个许可。当这些方法在不确定公平的情况下使用时,要注意增加的无限期推迟的风险。
    static final class FairSync extends Sync {
        private static final long serialVersionUID = 2014338818796000944L;

        FairSync(int permits) {
            super(permits);
        }

        protected int tryAcquireShared(int acquires) {
            for (;;) {
                if (hasQueuedPredecessors())
                    return -1;
                //*********state控制许可数量从而控制线程执行数量***开始***//
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
                //*********state控制许可数量从而控制线程执行数量***结束***//
            }
        }
    }

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Java程序员调优

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

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

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

打赏作者

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

抵扣说明:

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

余额充值