java 多线程 28 : 多线程组件之 Semaphore 信号量

Semaphore是非常有用的一个组件,它相当于是一个并发控制器,是用于管理信号量的。构造的时候传入可供管理的信号量的数值,这个数值就是控制并发数量的,就是同时能几个线程访问。我们需要控制并发的代码,执行前先通过acquire方法获取信号,执行后通过release归还信号 。每次acquire返回成功后,Semaphore可用的信号量就会减少一个,如果没有可用的信号,acquire调用就会阻塞,等待有release调用释放信号后,acquire才会得到信号并返回。

ps:注意这里信号量acquire方法和release方法是可以有参数的,表示获取/返还的信号量个数,如果不指定就是默认单个释放

Semaphore实现的功能就类似厕所有5个坑,假如有10个人要上厕所,那么同时只能有多少个人去上厕所呢?同时只能有5个人能够占用,当5个人中 的任何一个人让开后,其中等待的另外5个人中又有一个人可以占用了。另外等待的5个人中可以是随机获得优先机会,也可以是按照先来后到的顺序获得机会,这取决于构造Semaphore对象时传入的参数选项。单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。Semaphore在实现这种排队机制的时候很优秀,代码简洁

Semaphore维护了当前访问的个数,提供同步机制,控制同时访问的个数。在数据结构中链表可以保存“无限”的节点,用Semaphore可以实现有限大小的链表。另外重入锁 ReentrantLock 也可以实现该功能,但实现上要复杂些。

ReentrantLock 实现的生产/消费者一对一情况下 ,对比Semaphore 代码更复杂,但是在多个生产/消费的况,ReentrantLock虽然代码比较复杂,但是更高效 

Semaphore分为单值和多值两种:

1、单值的Semaphore管理的信号量只有1个,该信号量只能被1个,只能被一个线程所获得,意味着并发的代码只能被一个线程运行,这就相当于是一个互斥锁了

2、多值的Semaphore管理的信号量多余1个,主要用于控制并发数

看一下代码例子:

public static void main(String[] args)
{
    final Semaphore semaphore = new Semaphore(5);

    Runnable runnable = new Runnable()
    {
        public void run()
        {
            try
            {
                semaphore.acquire();                              System.out.println(Thread.currentThread().getName() + "获得了信号量,时间为" + System.currentTimeMillis());
                Thread.sleep(2000);
          System.out.println(Thread.currentThread().getName() + "释放了信号量,时间为" + System.currentTimeMillis());
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            finally
            {
                semaphore.release();
            }
        }
    };

    Thread[] threads = new Thread[10];
    for (int i = 0; i < threads.length; i++)
        threads[i] = new Thread(runnable);
    for (int i = 0; i < threads.length; i++)
        threads[i].start();
}

看一下运行结果:

 1 Thread-1获得了信号量,时间为1444557040464
 2 Thread-2获得了信号量,时间为1444557040465
 3 Thread-0获得了信号量,时间为1444557040464
 4 Thread-3获得了信号量,时间为1444557040465
 5 Thread-4获得了信号量,时间为1444557040465
 6 Thread-2释放了信号量,时间为1444557042466
 7 Thread-4释放了信号量,时间为1444557042466
 8 Thread-0释放了信号量,时间为1444557042466
 9 Thread-1释放了信号量,时间为1444557042466
10 Thread-3释放了信号量,时间为1444557042466
11 Thread-9获得了信号量,时间为1444557042467
12 Thread-7获得了信号量,时间为1444557042466
13 Thread-6获得了信号量,时间为1444557042466
14 Thread-5获得了信号量,时间为1444557042466
15 Thread-8获得了信号量,时间为1444557042467
16 Thread-9释放了信号量,时间为1444557044467
17 Thread-6释放了信号量,时间为1444557044467
18 Thread-7释放了信号量,时间为1444557044467
19 Thread-5释放了信号量,时间为1444557044468
20 Thread-8释放了信号量,时间为1444557044468

前10行为一部分,运行的线程是1 2 0 3 4,看到时间差也都是代码约定的2秒;后10行为一部分,运行的线程是9 7 6 5 8,时间差也都是约定的2秒,这就体现出了Semaphore的作用了,这里由于是在中间使用sleep ,所以看起来是有序的,必须释放5个才能获取,其实不然,是一个释放,信号量发现还有空余的就会立刻分给下一个等待的线程

这种通过Semaphore控制并发并发数的方式和通过控制线程数来控制并发数的方式相比,粒度更小,因为Semaphore可以通过acquire方法和release方法来控制代码块的并发数。

最后注意两点:

1、Semaphore可以指定公平锁还是非公平锁

2、acquire方法和release方法是可以有参数的,表示获取/返还的信号量个数

时间: 2025-01-04 05:03:19

java 多线程 28 : 多线程组件之 Semaphore 信号量的相关文章

java中的JUC组件(Semaphore、CountDownLatch、CyclicBarrier)

目录 1.简介 2.Semaphore 3.CountDownLatch 4.CyclicBarrier 1.简介 Semaphore.CountDownLatch.CyclicBarrier 这三个工具类都是用于并发控制的操作,底层都是基于AQS去实现的: Semaphore(信号量): 提供一个竞争资源处理的工具,当系统内有足够的信号量事,线程可以去获取信号量执行操作,当信号量资源被使用完后,需要等待资源释放后后续线程(资源竞争)才能够执行: CountDownLatch(闭锁):可以理解为

Cocoa多线程编程之block与semaphore(信号量)

首先大家要了解 dispatch_queue 的运作机制及线程同步 我们可以将许多 blocks 用 dispatch_async 函数提交到 dispatch_queue ,如果类型是DISPATCH_QUEUE_SERIAL (串行),那么这些 block 是按照 FIFO (先入先出)的规则调度的,也就是说,先加入的先执行,后加入的一定后执行,但在如果类型是DISPATCH_QUEUE_CONCURRENT(并行),那么某一时刻就可能有多个 block 同时在执行. 这个时候,如果两个 b

Java中使用多线程、curl及代理IP模拟post提交和get访问

Java中使用多线程.curl及代理IP模拟post提交和get访问 菜鸟,多线程好玩就写着玩,大神可以路过指教,小弟在这受教,谢谢! [java] view plaincopyprint? /** * @组件名:javaDemo * @包名:javaDemo * @文件名:Jenny.java * @创建时间: 2014年8月1日 下午5:53:48 * @版权信息:Copyright ? 2014 eelly Co.Ltd,小姨子版权所有. */ package javaDemo; impo

Java中的 多线程编程

Java 中的多线程编程 一.多线程的优缺点 多线程的优点: 1)资源利用率更好2)程序设计在某些情况下更简单3)程序响应更快 多线程的代价: 1)设计更复杂虽然有一些多线程应用程序比单线程的应用程序要简单,但其他的一般都更复杂.在多线程访问共享数据的时候,这部分代码需要特别的注意.线程之间的交互往往非常复杂.不正确的线程同步产生的错误非常难以被发现,并且重现以修复. 2)上下文切换的开销当CPU从执行一个线程切换到执行另外一个线程的时候,它需要先存储当前线程的本地的数据,程序指针等,然后载入另

Java中使用多线程、curl及代理IP模拟post提交和get訪问

Java中使用多线程.curl及代理IP模拟post提交和get訪问 菜鸟,多线程好玩就写着玩.大神能够路过不吝赐教.小弟在这受教.谢谢! 很多其它分享请关注微信公众号:lvxing1788 ~~~~~~ 切割线扭起来 ~~~~~~ /** * @组件名:javaDemo * @包名:javaDemo * @文件名称:Jenny.java * @创建时间: 2014年8月1日 下午5:53:48 * @版权信息:Copyright ? 2014 eelly Co.Ltd,小姨子版权全部. */

Java中的多线程技术全面详解

本文主要从整体上介绍Java中的多线程技术,对于一些重要的基础概念会进行相对详细的介绍,若有叙述不清晰或是不正确的地方,希望大家指出,谢谢大家:) 为什么使用多线程 并发与并行 我们知道,在单核机器上,"多进程"并不是真正的多个进程在同时执行,而是通过CPU时间分片,操作系统快速在进程间切换而模拟出来的多进程.我们通常把这种情况成为并发,也就是多个进程的运行行为是"一并发生"的,但不是同时执行的,因为CPU核数的限制(PC和通用寄存器只有一套,严格来说在同一时刻只能

Java线程及多线程技术及应用

第6 章 Java线程及多线程技术及应用 6.1线程基本概念 1.进程和线程的基础知识 l 进程:运行中的应用程序称为进程,拥有系统资源(cpu.内存) l 线程:进程中的一段代码,一个进程中可以哦有多段代码.本身不拥有资源(共享所在进程的资源) 在java中,程序入口被自动创建为主线程,在主线程中可以创建多个子线程. 区别: 1.是否占有资源问题 2.创建或撤销一个进程所需要的开销比创建或撤销一个线程所需要的开销大. 3.进程为重量级组件,线程为轻量级组件 l 多进程: 在操作系统中能同时运行

聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore

前几篇分析了一下AQS的原理和实现.这篇拿Semaphore信号量做样例看看AQS实际是怎样使用的. Semaphore表示了一种能够同一时候有多个线程进入临界区的同步器,它维护了一个状态表示可用的票据,仅仅有拿到了票据的线程尽能够进入临界区,否则就等待.直到获得释放出的票据. Semaphore经常使用在资源池中来管理资源.当状态仅仅有1个0两个值时,它退化成了一个相互排斥的同步器.类似锁. 以下来看看Semaphore的代码. 它维护了一个内部类Sync来继承AQS,定制tryXXX方法来使

Java学习笔记—多线程(java.util.concurrent并发包概括,转载)

一.描述线程的类:Runable和Thread都属于java.lang包 二.内置锁synchronized属于jvm关键字,内置条件队列操作接口Object.wait()/notify()/notifyAll()属于java.lang包 二.提供内存可见性和防止指令重排的volatile属于jvm关键字 四.而java.util.concurrent包(J.U.C)中包含的是java并发编程中有用的一些工具类,包括几个部分: 1.locks部分:包含在java.util.concurrent.