Java中的Semaphore信号量深入解析

 更新时间:2023年11月20日 10:21:02   作者:♛薄情痞子♛  
这篇文章主要介绍了Java中的Semaphore信号量深入解析,Semaphore是Java里面另外一个基本的并发工具包类,主要的的作用是用来保护共享资源的访问的,也就是仅仅允许一定数量的线程访问共享资源,需要的朋友可以参考下

Semaphore信号量

Semaphore是Java里面另外一个基本的并发工具包类,主要的的作用是用来保护共享资源的访问的,也就是仅仅允许一定数量的线程访问共享资源。

Semaphore维护了有限数量的许可证,只有得到了许可证的线程才能进行共享资源的访问,如果得不到许可证,说明当前共享资源的访问已经达到最大限制,所以会挂起当前线程,直到前面的线程处理完任务之后,把许可证归还,后面排队的线程才有机会获取,然后处理任务。

这里面有两个注意点:

(1)大多数时候使用Semaphore都应该是公平模式,默认是非公平模式,如果需要公平模式可以在构造函数里面指定,公平性可以 保证先进先出,不会有线程饥饿问题出现,非公平模式,不保证顺序,吞吐量会更好一些。

(2)共享资源的访问,一般指的是读取,而不是更新,这里面不要做对共享变量的修改,除非你使用同步块来保证。

下面我们来看下Semaphore的构造方法:

Semaphore(int permits) //非公平模式指定最大允许访问许可证数量
Semaphore(int permits, boolean fair)//可以通过第二个参数控制是否使用公平模

一些常用的方法:

acquire() //申请获取一个许可证,如果没有许可证,就阻塞直到能够获取或者被打断
availablePermits() // 返回当前有多少个有用的许可证数量hasQueuedThreads()//查询是否有线程正在等待获取许可证
drainPermits()//获得并返回所有立即可用的许可证数量
getQueuedThreads()//返回一个List包含当前可能正在阻塞队列里面所有线程对象
getQueueLength()//返回当前可能在阻塞获取许可证线程的数量
hasQueuedThreads()//查询是否有线程正在等待获取许可证
isFair()//返回是否为公平模式
reducePermits(int reduction)//减少指定数量的许可证
reducePermits(int reduction)//释放一个许可证
release(int permits)//释放指定数量的许可证
tryAcquire()//非阻塞的获取一个许可证

无论是Semaphore还是CountDonwLatch或者是CyclicBarrier,其实我们都可以通过Lock接口+Condition条件队列功能来模拟实现,但是不够抽象所以才出现了AQS这个抽象的面向开发者同步框架,比如这个Semaphore,我们看下如何使用Lock实现:

public class SemaphoreDemo2 {
 
    private final Lock lock=new ReentrantLock(true);
    private final Condition condition=lock.newCondition();
    private int permit;
    public SemaphoreDemo2(int permit) {
        this.permit=permit;
    }
 
 
    private void acquire(){
 
        lock.lock();
        try{
            if(permit==0){
                condition.await();//如果超过限制,就进入条件阻塞队列
            }
            System.out.println(Thread.currentThread().getName()+"  获得资源 .... ");
             permit--;
 
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
 
    }
 
 
    private void  release(){
        lock.lock();
        try{
            permit++;
            condition.signalAll(); //每当有一个释放令牌,就唤醒所有等待的线程
        }finally {
            lock.unlock();
        }
 
 
    }
 
 
}

下面我们看一下简单的使用例子:

Semaphore semaphore=new Semaphore(3);
 
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                try {
                    semaphore.acquire();
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " 访问资源......");
                    semaphore.release();
            }
        };
 
        for (int i = 0; i < 5; i++) {
            Thread thread=new Thread(runnable);
            thread.start();
        }
 
        Thread.sleep(3000);

输出结果:

Thread-0 访问资源......
Thread-1 访问资源......
Thread-2 访问资源......
Thread-4 访问资源......
Thread-3 访问资源......

注意上面的例子只有3个许可证,我们运行了5个线程,所以同时最多只能运行3个线程,另外两个会阻塞直到前面的线程归还了许可证。

Semaphore底层原理:

Semaphore底层与CountDownLatch类似都是通过AQS的共享锁机制来实现的,指定的数量会设置到AQS里面的state里面,然后对于每一个 调用acquire方法线程,state都会减去一,如果state等于0,那么调用该方法的线程会被添加到同步队列里面,同时使用 LockSupport.park方法挂起等待,知道有线程调用了release方法,会对state加1,然后唤醒共享队列里面的线程,注意这里如果是 公平模式,就直接唤醒下一个等待线程即可,如果是非公平模式就允许新加入的线程与已有的线程进行竞争,谁先得到就是谁的,如果新加入的 竞争失败,就会走公平模式进入队列排队。

总结:

本文主要介绍了并发工具包Semaphore其主要作用来限制对于共享资源的访问,接着我们又介绍了其特点,使用及注意事项,然后又给出了使用其他同步工具Lock+Condition实现的Semaphore

到此这篇关于Java中的Semaphore信号量深入解析的文章就介绍到这了,更多相关Semaphore信号量深入解析内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java基于jdbc连接mysql数据库功能实例详解

    java基于jdbc连接mysql数据库功能实例详解

    这篇文章主要介绍了java基于jdbc连接mysql数据库功能,结合实例形式详细分析了jdbc连接mysql数据库的原理、步骤、实现方法及相关操作技巧,需要的朋友可以参考下
    2017-10-10
  • 使用bat启动springboot项目并解决乱码问题

    使用bat启动springboot项目并解决乱码问题

    这篇文章主要介绍了window中使用bat启动springboot项目,并解决乱码问题
    2021-06-06
  • Java实现Huffman编码的示例代码

    Java实现Huffman编码的示例代码

    Huffman编码是一种编码方式,本文主要介绍了Java实现Huffman编码的示例代码,具有一定的参考价值,感兴趣的可以了解一下
    2023-08-08
  • Java虚拟机JVM性能优化(二):编译器

    Java虚拟机JVM性能优化(二):编译器

    这篇文章主要介绍了Java虚拟机JVM性能优化(二):编译器,本文先是讲解了不同种类的编译器,并对客户端编译,服务器端编译器和多层编译的运行性能进行了对比,然后给出了几种常见的JVM优化方法,需要的朋友可以参考下
    2014-09-09
  • Java集合的总体框架相关知识总结

    Java集合的总体框架相关知识总结

    今天带大家学习Java集合框架的相关知识,文中有非常详细的图文介绍,对正在学习Java的小伙伴们很有帮助,需要的朋友可以参考下
    2021-05-05
  • java实战小技巧之字符串与容器互转详解

    java实战小技巧之字符串与容器互转详解

    Java.lang.String是Java的字符串类. Srting是一个不可变对象,下面这篇文章主要给大家介绍了关于java实战小技巧之字符串与容器互转的相关资料,需要的朋友可以参考下
    2021-08-08
  • 浅析java修饰符访问权限(动力节点Java学院整理)

    浅析java修饰符访问权限(动力节点Java学院整理)

    Java有四种访问权限,其中三种有访问权限修饰符,分别为private,public和protected,还有一种不带任何修饰符,下面通过本文给大家简单介绍下java修饰符访问权限相关知识,感兴趣的朋友一起学习吧
    2017-04-04
  • Java正则表达式的实例操作指南

    Java正则表达式的实例操作指南

    这篇文章主要给大家介绍了关于Java正则表达式的实例操作指南,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Springboot整合JwtHelper实现非对称加密

    Springboot整合JwtHelper实现非对称加密

    本文主要介绍了Springboot整合JwtHelper实现非对称加密,主要介绍两种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-03-03
  • Future与FutureTask接口实现示例详解

    Future与FutureTask接口实现示例详解

    这篇文章主要为大家介绍了Future与FutureTask接口实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10

最新评论