信号量Semaphore企业应用

简介:信号量是JUC中重要的一员,常用来做线程同步和通信控制。

I 基础操作:

①初始化

//进行初始化时需要提供一个初始信号量大小
private Semaphore permitTickets = new Semaphore(7);

②获取信号量

//在业务操作前进行获取信号操作,如获取不到则阻塞等待,否则获取到后总信号量数量减一
permitTickets.acquire();

③释放信号量

//业务操作完成后释放信号操作,信号总量加一
permitTickets.release();

④推荐写法

try {
    permitTickets.acquire();
    // do something
} finally {
    if (permitTickets != null) {
        permitTickets.release();
    }
}

⑤示例如图

II 应用

①生产者消费者场景中,消费者多线程消费控制

  1. 描述:生产者与消费者问题常使用MQ来处理之间的通信,此时当生产者能力大于消费者时,会造成消息的堆积,此时可采用死信队列延迟少量推送,但终究还是需要加快消息的处理能力,即引入线程和线程池。线程池有几个关键参数:核心线程数、最大线程数、阻塞队列,其能存放的最大线程数量为最大线程数+阻塞队列容量,再次提交时将触发四种拒绝策略之一。
  2. 存在问题:
  • 无法将队列容量设置成较大的准确值
  • 如果阻塞队列为无界队列,则大量消息过来时将可能OOM,此时全部消息将直接丢弃
  • AbortPolicy,DiscardOledestPolicy、DiscardPolicy拒绝策略触发时导致消息丢弃
  • CallerRunsPolicy策略将任务交给主线程将影响主线程继续提交子任务
  1. 解决方案

使用Semaphore信号量控制线程主线程提交的任务数,信号量初始值大小为最大线程数+阻塞队列容量

private static Semaphore permitTickets = new Semaphore(7);

public static void main(String[] args) throws InterruptedException {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2));
    for (int i = 0;i < 8; i++) {
        permitTickets.acquire();
        int finalI = i;
        threadPoolExecutor.execute(() -> {
            try {
                System.out.println("【" + finalI + "线程】正在执行!");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                permitTickets.release();
            }
        });
    }
    System.out.println("【Main】添加线程完成!");
    Thread.sleep(5000);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值