一.概念理解

有关Semaphore(信号量),你会看到有关材料是这样解释的:信号量是用来控制同时访问特定资源的线程数量,它通过协调各个线程,保证合理的使用公共资源。线程可以通过acquire() 方法来获取信号量的许可,当信号量中没有可用的许可的时候,线程阻塞,直到有可用的许可为止。线程可以通过release()方法释放它持有的信号量的许可。

这里面我举个例子:比如你想去一家餐馆吃饭,这家餐馆总共同时供应100人就餐,如果餐馆已经满员了,你想进去吃饭就需要排号等待,直到有客人吃完离开。你才可以进入。这里所说的餐馆我们就可以看作是线程池,餐馆里的服务员好比共享资源,每位客人都好比一个线程。Semaphore(信号量)就记录着里面的人数,要根据Semaphore(信号量)的数量来决定是否可以进入新的客人。

二.方法列表

1.构造方法:

// 创建具有给定的许可数和非公平的公平设置的 Semaphore。
Semaphore(int permits)
// 创建具有给定的许可数和给定的公平设置的 Semaphore。
Semaphore(int permits, boolean fair)

2.方法:

// 从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。
void acquire()
// 从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞,或者线程已被中断。
void acquire(int permits)
// 从此信号量中获取许可,在有可用的许可前将其阻塞。
void acquireUninterruptibly()
// 从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞。
void acquireUninterruptibly(int permits)
// 返回此信号量中当前可用的许可数。
int availablePermits()
// 获取并返回立即可用的所有许可。
int drainPermits()
// 返回一个 collection,包含可能等待获取的线程。
protected Collection<Thread> getQueuedThreads()
// 返回正在等待获取的线程的估计数目。
int getQueueLength()
// 查询是否有线程正在等待获取。
boolean hasQueuedThreads()
// 如果此信号量的公平设置为 true,则返回 true。
boolean isFair()
// 根据指定的缩减量减小可用许可的数目。
protected void reducePermits(int reduction)
// 释放一个许可,将其返回给信号量。
void release()
// 释放给定数目的许可,将其返回到信号量。
void release(int permits)
// 返回标识此信号量的字符串,以及信号量的状态。
String toString()
// 仅在调用时此信号量存在一个可用许可,才从信号量获取许可。
boolean tryAcquire()
// 仅在调用时此信号量中有给定数目的许可时,才从此信号量中获取这些许可。
boolean tryAcquire(int permits)
// 如果在给定的等待时间内此信号量有可用的所有许可,并且当前线程未被中断,则从此信号量获取给定数目的许可。
boolean tryAcquire(int permits, long timeout, TimeUnit unit)
// 如果在给定的等待时间内,此信号量有可用的许可并且当前线程未被中断,则从此信号量获取一个许可。
boolean tryAcquire(long timeout, TimeUnit unit)

三.源码

Semaphore是通过共享锁实现的。根据共享锁的获取原则,Semaphore分为"公平信号量"和"非公平信号量"。"公平信号量"和"非公平信号量"的释放信号量的机制是一样的,不同的是它们获取信号量的机制,线程在尝试获取信号量许可时,对于公平信号量而言,如果当前线程不在CLH队列的头部,则排队等候;而对于非公平信号量而言,无论当前线程是不是在CLH队列的头部,它都会直接获取信号量。该差异具体的体现在它们的tryAcquireShared()函数的实现不同。实现如下:

1."非公平信号量"类

static final class NonfairSync extends Sync {private static final long serialVersionUID = -2694183684443567898L;NonfairSync(int permits) {super(permits);}protected int tryAcquireShared(int acquires) {return nonfairTryAcquireShared(acquires);}
}

2."公平信号量"类

static final class FairSync extends Sync {private static final long serialVersionUID = 2014338818796000944L;FairSync(int permits) {super(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;}}
}

四.实例演示

public class SemaphoreDemo {private static final int THREAD_COUNT = 20;private static ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);// 创建5个许可,允许5并发执行private static Semaphore s = new Semaphore(5);public static void main(String[] args) {// 创建20个线程执行任务for (int i = 0; i < THREAD_COUNT; i++) {executorService.execute(new Runnable() {@Overridepublic void run() {try {// 同时只能有5个线程并发执行保存数据的任务s.acquire();System.out.println("线程-》 " + Thread.currentThread().getName() + " ---》保存数据");Thread.sleep(1000);// 5个线程保存完数据,释放1个许可,其他的线程才能获取许可,继续执行保存数据的任务s.release();System.out.println("线程-》 " + Thread.currentThread().getName() + " ---》释放许可");} catch (InterruptedException e) {e.printStackTrace();}}});}// 关闭线程池executorService.shutdown();}
}

运行结果:

线程-》 pool-1-thread-1 ---》保存数据
线程-》 pool-1-thread-5 ---》保存数据
线程-》 pool-1-thread-2 ---》保存数据
线程-》 pool-1-thread-3 ---》保存数据
线程-》 pool-1-thread-4 ---》保存数据
线程-》 pool-1-thread-3 ---》释放许可
线程-》 pool-1-thread-7 ---》保存数据
线程-》 pool-1-thread-6 ---》保存数据
线程-》 pool-1-thread-5 ---》释放许可
线程-》 pool-1-thread-1 ---》释放许可
线程-》 pool-1-thread-4 ---》释放许可
线程-》 pool-1-thread-2 ---》释放许可
线程-》 pool-1-thread-10 ---》保存数据
线程-》 pool-1-thread-8 ---》保存数据
线程-》 pool-1-thread-9 ---》保存数据
线程-》 pool-1-thread-6 ---》释放许可
线程-》 pool-1-thread-12 ---》保存数据
线程-》 pool-1-thread-11 ---》保存数据
线程-》 pool-1-thread-7 ---》释放许可
线程-》 pool-1-thread-10 ---》释放许可
线程-》 pool-1-thread-13 ---》保存数据
线程-》 pool-1-thread-8 ---》释放许可
线程-》 pool-1-thread-15 ---》保存数据
线程-》 pool-1-thread-14 ---》保存数据
线程-》 pool-1-thread-9 ---》释放许可
线程-》 pool-1-thread-12 ---》释放许可
线程-》 pool-1-thread-16 ---》保存数据
线程-》 pool-1-thread-11 ---》释放许可
线程-》 pool-1-thread-17 ---》保存数据
线程-》 pool-1-thread-13 ---》释放许可
线程-》 pool-1-thread-18 ---》保存数据
线程-》 pool-1-thread-15 ---》释放许可
线程-》 pool-1-thread-19 ---》保存数据
线程-》 pool-1-thread-14 ---》释放许可
线程-》 pool-1-thread-20 ---》保存数据
线程-》 pool-1-thread-16 ---》释放许可
线程-》 pool-1-thread-17 ---》释放许可
线程-》 pool-1-thread-18 ---》释放许可
线程-》 pool-1-thread-19 ---》释放许可
线程-》 pool-1-thread-20 ---》释放许可

Java中的并发工具类:Semaphore基本理解和底层实现相关推荐

  1. 《Java并发编程的艺术》——Java中的并发工具类、线程池、Execute框架(笔记)

    文章目录 八.Java中的并发工具类 8.1 等待多线程完成的CountDownLatch 8.2 同步屏障CyclicBarrier 8.2.1 CyclicBarrier简介 8.2.2 Cycl ...

  2. 《Java并发编程的艺术》读后笔记-Java中的并发工具类(第八章)

    文章目录 <Java并发编程的艺术>读后笔记-Java中的并发工具类(第八章) 1.等待多线程完成的CountDownLatch 2.同步屏障CyclicBarrier 2.1 Cycli ...

  3. Java 中的并发工具类

    From: https://blog.wuwii.com/juc-utils.html java.util.concurrent 下提供了一些辅助类来帮助我们在并发编程的设计. 学习了 AQS 后再了 ...

  4. 【搞定Java并发编程】第24篇:Java中的并发工具类之CountDownLatch

    上一篇:Java中的阻塞队列 BlockingQueue 详解 本文目录: 1.CountDownLatch的基本概述 2.CountDownLatch的使用案例 3.CountDownLatch的源 ...

  5. 《Java并发编程的艺术》读书笔记 - 第八章 - Java中的并发工具类

    目录 前言 等待多线程完成的 CountDownLatch 示例 同步屏障 CyclicBarrier 示例 CyclicBarrier 和 CountDownLatch 的区别 控制并发线程数量的 ...

  6. 第8章 java中的并发工具类

    8.1 等待线程完成的CountDownLatch 作用:让一个线程等待其余线程完成之后在继续执行,如主线程等待开启服务的子线程执行完毕后主线程继续执行,类似于join. 转载于:https://ww ...

  7. java ftp ftpclient_详解JAVA中使用FTPClient工具类上传下载

    详解JAVA中使用FTPClient工具类上传下载 在Java程序中,经常需要和FTP打交道,比如向FTP服务器上传文件.下载文件.本文简单介绍如何利用jakarta commons中的FTPClie ...

  8. java中常用的工具类

    1. 常用零散工具类 1.1[DateUtil.java]日期处理的工具类 /*** 时间日期处理工具* String -> Date* Date -> String* 以及生成含有日期的 ...

  9. Java并发工具类Semaphore应用实例

    1 package com.thread.test.thread; 2 3 import java.util.Random; 4 import java.util.concurrent.*; 5 6 ...

  10. Java中使用UUID工具类生成唯一标志防止重复

    场景 UUID 是指Universally Unique Identifier,翻译为中文是通用唯一识别码,UUID 的目的是让分布式系统中的所有元素都能有唯一的识别信息. 在某些场景下需要给数据库中 ...

最新文章

  1. 算法 判断多个点是否在同一圆周线上_凸包问题——礼物包裹算法
  2. Linux下程序报出/bin/bash: No such file or directory
  3. 读取文件中的文本并返回字符串
  4. 多态——面向接口编程
  5. 019.nexus搭建docker镜像仓库/maven仓库
  6. Knowledge Integration Networks for Action Recognition AAAI 2020
  7. 总结ubuntu 在命令界面login incorrect的问题
  8. Net-Snmp安装配置
  9. 简单html图片轮播_抖音图片轮播的视频怎么制作?小白1分钟就能学会,超简单...
  10. Day83.尚好房 — 用户管理— Hplus(UI框架)、Layer(弹出层框架)、增删改查、分页组件 :分页查询
  11. 华为2022校园赛——车道渲染
  12. Layabox 屏幕适配
  13. 蜂考c语言、数据结构(课后习题答案)
  14. 【子网,超网和掩码】
  15. 爱普生Epson PictureMate 240 打印机驱动
  16. (CSU - 1224)ACM小组的古怪象棋
  17. LaTeX - 星形线(内摆线的一种)
  18. 11_ue4天空球的使用
  19. Vue Language Features (Volar) 会引起ts报错
  20. 中国氢电解槽市场深度研究分析报告

热门文章

  1. SAM4E单片机之旅——11、UART之PDC收发
  2. 简单的java图像裁减
  3. javafx将数据库内容输出到tableview表格
  4. Restful 风格
  5. BZOJ4519 CQOI2016不同的最小割(最小割+分治)
  6. Maven中配置redis时有红色感叹号
  7. 2017-7-8 OpenStack手工+oz自动制作CentOS 7.3镜像
  8. json解析与序列化
  9. 解决“在上下文中找不到 owin.Environment 项”
  10. strictmode