当前位置: 首页 > news >正文

Semaphore

关于作者: CSDN内容合伙人、技术专家, 从零开始做日活千万级APP,带领团队单日营收超千万。
专注于分享各领域原创系列文章 ,擅长java后端、移动开发、商业化变现、人工智能等,希望大家多多支持。

目录

  • 一、导读
  • 二、概览
  • 三、使用
  • 四、原理
  • 五、 推荐阅读

ddd

一、导读

我们继续总结学习Java基础知识,温故知新。
本文涉及知识点:
AQS - AbstractQueuedSynchronizer
CAS(Compare And Swap)
锁概念 volatile

二、概览

ˈseməfɔː®

Semaphore 是信号量的意思,作用是控制访问特定资源的线程数量。
在多线程环境下用于协调各个线程, 以保证它们能够正确、合理的使用公共资源
Semaphore叫做信号量,和 CountDownLatch CyclicBarrier 两个不同的是,他的计数器是递增的。

三、使用

控制访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,常用于限流
如:买火车票,游乐场设施。

Semaphore在构造的时候, 可以传入一个int. 表示有多少许可(permit). 线程获取锁的时候, 要告诉信号量使用多少许可, 当线程要使用的许可不足时, 则调用的线程则会被阻塞.

游乐园中的某个游乐设施的管理员,用来控制同时玩这个游乐设施的人数。比如跳楼机只能坐十个人,就设置 Semaphore 的 permits 等于 10

public class SemaphoreTest {
    public static void main(String[] args) {
        //创建permits等于2
        Semaphore semaphore=new Semaphore(2);
        //开五个线程去执行PlayGame
        for (int i = 0; i < 5; i++) {
            new Thread(new PlayGame(semaphore)).start();
        }
    }

    static class PlayGame extends Thread{
        Semaphore semaphore;
        public PlayGame(Semaphore semaphore){
            this.semaphore=semaphore;
        }
        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName()+"获得一个许可证");
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+"释放一个许可证");
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

四、原理

利用了 AQS - AbstractQueuedSynchronizer 的共享锁来实现,同时获取信号量有公平和非公平两种策略。

我们来看下源码

// 1、初始化,传人最大资源数
public Semaphore(int permits)

acquire()  
获取一个令牌,在获取到令牌、或者被其他线程调用中断之前线程一直处于阻塞状态。
调用Semaphore#acquire() 方法, 它本质上是调用的AQS#acquireSharedInterruptibly(int), 参数为1
// 调用 AQS#doAcquireSharedInterruptibly(1) 方法acquire(int permits)  
获取一个令牌,在获取到令牌、或者被其他线程调用中断、或超时之前线程一直处于阻塞状态。
    
acquireUninterruptibly() 
获取一个令牌,在获取到令牌之前线程一直处于阻塞状态(忽略中断)。
    
tryAcquire()
尝试获得令牌,返回获取令牌成功或失败,不阻塞线程。
​
tryAcquire(long timeout, TimeUnit unit)
尝试获得令牌,在超时时间内循环尝试获取,直到尝试获取成功或超时返回,不阻塞线程。
​
release()
释放一个令牌,唤醒一个获取令牌不成功的阻塞线程。

drainPermits()
清空令牌把可用令牌数置为0,返回清空令牌的数量。
​
availablePermits()
返回可用的令牌数量。

Semaphore的内部类公平锁(FairSync)和非公平锁(NoFairSync)各自实现不同的获取锁方法,默认公平锁。

在这里插入图片描述

子类的任务有:
1.通过CAS操作维护共享变量state。
2.重写资源的获取方式。
3.重写资源释放的方式。

1.主线程调用acquire()方法时,用当前信号量值-需要获取的值,如果小于0,则进入同步阻塞队列,大于0则通过CAS设置当前信号量为剩余值,同时返回剩余值
2.子线程调用release()给当前信号量值计数器+1(增加的值数量由传参决定),同时不停的尝试因为调用acquire()进入阻塞的线程

/**
     *  获取1个令牌
     */
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

五、 推荐阅读

Java 专栏

SQL 专栏

数据结构与算法

Android学习专栏

在这里插入图片描述

相关文章:

  • deepseek使用记录26——从体力异化到脑力异化
  • 牛客周赛 + 洛谷刷题
  • 区块链技术:重塑供应链管理的未来
  • 【合新通信】数据中心-浸没式液冷环境中氟化液防泄漏设计方法
  • INFINI Labs 产品更新 | Coco AI 0.3 发布 – 新增支持 Widget 外部站点集成
  • vue3+element-plus动态与静态表格数据渲染
  • 【C++】vector的底层封装和实现
  • 鬼泣总结:玩家攻击warp
  • 如何对LLM大型语言模型进行评估与基准测试
  • 【数据集】最新上市公司创新信息披露(1991-2023年)
  • 沧州铁狮子
  • 计算机专业求职面试的常见题目分类整理
  • Navicat 17.2:AI 支持与云功能升级驱动更智能的数据库管理
  • 我的NISP二级之路-02
  • c++string的简单模拟实现
  • 详细解读ts中的函数重载
  • LiT and Lean: Distilling Listwise Rerankers intoEncoder-Decoder Models
  • 佳能imageRUNNER 2935复印机调整休眠时间方法
  • Meta LLaMA 4:对抗 GPT-4o 与 Claude 的开源王牌
  • 【教学类-102-05】蛋糕剪纸图案(留白边、沿线剪)04——Python白色(255)图片转为透明png再制作“点状边框和虚线边框”
  • 互动交流平台/兰州seo关键词优化
  • 活动策划网站有哪些/西安网站seo排名优化
  • 建设厅网站如何查询企业信息网/微信营销推广
  • 编程和做网站那个号/谷歌seo代运营
  • 凡科论坛网站制作/网站免费建站app
  • 网站关键字个数/广州网站设计制作