面试官:说说Java中的信号量?Semaphore

简介: 面试官:说说Java中的信号量?Semaphore

Semaphore (信号量)是由计算机科学家Dijkstra在1965年提出的,广泛应用不同的操作系统,在管程提出之前信号量就是并发编程领域的霸主!几乎所有并发的语言都支持信号量机制。


Semaphore 也有被翻译成信号灯,因为其机制就像我们日常生活中的红绿灯,车辆的通行看红绿灯,对应编程世界的线程能不能执行得看信号灯!


Semaphore 用来多线程互斥问题,相对于synchronized和Lock来说它允许多个线程访问一个临界区!例如各种池:数据库连接池、对象池等,这些池的需求就是同一时刻允许多个线程同时使用连接池。


Semaphore的模型可以概括为一个计数器、一个等待队列、三个方法。 三个方法原子性分别是init()、down()、up()


init():设置计数器的初始值。


down():将计数器的值减一,如果减了一之后,计数器的值小于0,则当前的线程被阻塞,否则继续执行。


up():将计数器的值加一,如果加了一之后,计数器的值小于等于0,则唤醒等待队列中的一个线程,并且将它移除出等待队列。(注意是小于等于0,不应该理解为大于等于0,因为大于等于0表明此时没有等待的线程,所以不会有唤醒这个操作。)


image.png


简单的理解就是 Semaphore 就是通过这三个方法来改变计数器,通过计数器的值来判断此时的线程是应该加入到等待队列中等待还是成功执行。


信号量模型也被称为PV原语,也就是downup操作最早称为P操作和V操作,有些人还称为semWaitsemSignal在JAVA中信号量模型是由 java.util.concurrent.Semaphore 的实现,并且downup对应的实现方法是acquire和release,我们来看下简单的使用例子

int count;
    final Semaphore semaphore   = new Semaphore(1); // 初始化信号量
    // 用信号量保证互斥    
    void addOne() {
      try {
          semaphore.acquire();   //对应down
          count+=1;
        } catch (InterruptedException e) {
          e.printStackTrace();
        } finally {
          semaphore.release();  //对应up
        }
    }

如果你想多让几个线程进去临界区,那么就把Semaphore构造器中的1改为你想要的线程数。


可以理解为颁发许可证,比如想同时允许3个线程进入临界区,构造器中的数就填3,理解为搞了3张许可证,然后颁发出去,谁拿到了许可证谁就能进临界区,进入临界区后的线程搞完事了,就归还许可证,然后出去。


Semaphore的内部共存在Sync、NonfairSync、FairSync三个类,NonfairSyncFairSync类继承自Sync类,Sync类继承自AbstractQueuedSynchronizer抽象类,也就Semaphore是依托于NonfairSync、FairSync来实现的。


public Semaphore(int permits) {
          sync = new NonfairSync(permits);
      }
      public Semaphore(int permits, boolean fair) {
          sync = fair ? new FairSync(permits) : new NonfairSync(permits);
      }


可以通过构造函数来指定为公平锁还是非公平锁,公平的意思这个许可只会给按先来后到的顺序给等待队列中的线程。而非公平的意思就是对于任何申请许可的线程,都第一时间看是否有多余的许可,如果有则给此线程。


protected int tryAcquireShared(int acquires) {   //公平
            for (;;) {
                if (hasQueuedPredecessors())
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);   //非公平
        }
        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining)
                    return remaining;
            }
        }

差别就在于有没hasQueuedPredecessors(),这个方法就是判断当前线程是否是等待队列中的头结点,如果不是,则不给于分配。 大致Semaphore的模型和模型实现思路就是这样,建议多看看源码,不难的可以加深理解,并且懂得具体实现之后能掌握把控更多细节,还不怕面试官问。



相关文章
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
2月前
|
Java
JAVA并发编程系列(7)Semaphore信号量剖析
腾讯T2面试,要求在3分钟内用不超过20行代码模拟地铁安检进站过程。题目设定10个安检口,100人排队,每人安检需5秒。实际中,这种题目主要考察并发编程能力,特别是多个线程如何共享有限资源。今天我们使用信号量(Semaphore)实现,限制同时进站的人数,并通过信号量控制排队和进站流程。并详细剖析信号量核心原理和源码。
|
16天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
17天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
41 4
|
1月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
74 2
|
1月前
|
JSON 安全 前端开发
第二次面试总结 - 宏汉科技 - Java后端开发
本文是作者对宏汉科技Java后端开发岗位的第二次面试总结,面试结果不理想,主要原因是Java基础知识掌握不牢固,文章详细列出了面试中被问到的技术问题及答案,包括字符串相关函数、抽象类与接口的区别、Java创建线程池的方式、回调函数、函数式接口、反射以及Java中的集合等。
31 0
|
2月前
|
Java 数据中心 微服务
Java高级知识:线程池隔离与信号量隔离的实战应用
在Java并发编程中,线程池隔离与信号量隔离是两种常用的资源隔离技术,它们在提高系统稳定性、防止系统过载方面发挥着重要作用。
53 0
|
3月前
|
XML 存储 JSON
【IO面试题 六】、 除了Java自带的序列化之外,你还了解哪些序列化工具?
除了Java自带的序列化,常见的序列化工具还包括JSON(如jackson、gson、fastjson)、Protobuf、Thrift和Avro,各具特点,适用于不同的应用场景和性能需求。
|
3月前
|
缓存 Java
【IO面试题 一】、介绍一下Java中的IO流
Java中的IO流是对数据输入输出操作的抽象,分为输入流和输出流,字节流和字符流,节点流和处理流,提供了多种类支持不同数据源和操作,如文件流、数组流、管道流、字符串流、缓冲流、转换流、对象流、打印流、推回输入流和数据流等。
【IO面试题 一】、介绍一下Java中的IO流
|
3月前
|
C# Windows 开发者
当WPF遇见OpenGL:一场关于如何在Windows Presentation Foundation中融入高性能跨平台图形处理技术的精彩碰撞——详解集成步骤与实战代码示例
【8月更文挑战第31天】本文详细介绍了如何在Windows Presentation Foundation (WPF) 中集成OpenGL,以实现高性能的跨平台图形处理。通过具体示例代码,展示了使用SharpGL库在WPF应用中创建并渲染OpenGL图形的过程,包括开发环境搭建、OpenGL渲染窗口创建及控件集成等关键步骤,帮助开发者更好地理解和应用OpenGL技术。
264 0

热门文章

最新文章

下一篇
无影云桌面