Semaphore意思的信号量,它的作用是控制访问特定资源的线程数量

构造方法

public Semaphore(int permits)

public Semaphore(int permits, boolean fair)

  permits:允许同时访问的线程数量

  fair:是否公平,若true的话,下次执行的会是先进去等待的线程(先入先出)

使用

acquire():获取许可执行

release():释放许可,让其他线程获取许可执行。

显然这个功能可以用于资源访问控制或者是限流的操作。

如下代码每次只会有两个线程执行。

package com.nijunyang.concurrent;

import java.util.concurrent.Semaphore;

/**
* Description:
* Created by nijunyang on 2020/5/13 23:31
*/
public class SemaphoreTest {
Semaphore semaphore; public SemaphoreTest(Semaphore semaphore) {
this.semaphore = semaphore;
} public static void main(String[] args) {
SemaphoreTest semaphoreTest = new SemaphoreTest(new Semaphore(2, true));
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(() -> {
try {
semaphoreTest.test();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "线程" + i);
thread.start();
}
System.out.println("线程创建完毕.");
} public void test() throws InterruptedException {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "执行.");
Thread.sleep(4000);
semaphore.release();
}
}

原理

进入Semaphore的代码一看,又见到AQS,前面ReentrantLock中用到的是独占模式,Semaphore中就是共享模式了。和ReentrantLock如出一辙,内部类Sync继承了AbstractQueuedSynchronizer,同时有两个子类实现一个公平FairSync,另一个非公平NonfairSync。

构造方法传入的permits,最终会赋值到AbstractQueuedSynchronizer的state字段,这个字段的ReentrantLock中是用来计算锁重入的。但是在Semaphore里面字段是用来控制资源访问数量的。

1.acquire方法获取的许可的时候 先去扣减,将state的值-1,如果结果不小于0,就通过CAS操作修改state的值,最后返回当前剩余许可

2. 如果返回的许可剩余数量小于0 就执行doAcquireSharedInterruptibly方法,将当前线程以共享的模式加入到队列中去

3. 拿到前驱结点,根据结点的几个状态去判断前驱结点是否是取消或者其他状态,如果取消状态就剔除出去

4.release方法 释放许可  CAS操作将state的值+1

5.设置成功了执行doReleaseShared方法,去唤醒队列中等待的线程,获取到许可执行

Semaphore和AQS的更多相关文章

  1. Java并发(6)- CountDownLatch、Semaphore与AQS

    引言 上一篇文章中详细分析了基于AQS的ReentrantLock原理,ReentrantLock通过AQS中的state变量0和1之间的转换代表了独占锁.那么可以思考一下,当state变量大于1时代 ...

  2. Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例

    概要 本章,我们对JUC包中的信号量Semaphore进行学习.内容包括:Semaphore简介Semaphore数据结构Semaphore源码分析(基于JDK1.7.0_40)Semaphore示例 ...

  3. Java并发编程Semaphore

    信号量 信号量类Semaphore,用来保护对唯一共享资源的访问.一个简单的打印队列,并发任务进行打印,加入信号量同时之能有一个线程进行打印任务 . import java.util.concurre ...

  4. Java并发编程-Semaphore

    基于AQS的前世今生,来学习并发工具类Semaphore.本文将从Semaphore的应用场景.源码原理解析来学习这个并发工具类. 1. 应用场景 Semaphore用来控制同时访问某个特定资源的操作 ...

  5. J.U.C并发框架源码阅读(五)Semaphore

    基于版本jdk1.7.0_80 java.util.concurrent.Semaphore 代码如下 /* * ORACLE PROPRIETARY/CONFIDENTIAL. Use is sub ...

  6. 透过ReentrantLock窥探AQS

    背景 JDK1.5引入的并发包提供了一系列支持中等并发的类,这些组件是一系列的同步器,几乎任一同步器都可以实现其他形式的同步器,例如,可以用可重入锁实现信号量或者用信号量实现可重入锁.但是,这样做带来 ...

  7. 透过CountDownLatch窥探AQS

    本文来自公众号“Kahuna”,可搜索Alitaba119,欢迎关注,转载请注明出处,非常感谢 “ A synchronization aid that allows one or more thre ...

  8. Java并发指南9:AQS共享模式与并发工具类的实现

    一行一行源码分析清楚 AbstractQueuedSynchronizer (三) 转自:https://javadoop.com/post/AbstractQueuedSynchronizer-3 ...

  9. 1.3.4 并发工具类CountDownLatch/Semaphore/CyclicBarrier/FutureTask

    CountDownLatch的2个用途: 1. 所有线程都到达相同的起跑线后,再一起开始跑(并非同时开始,而是队列中一个唤醒另一个)[此情况需到达起跑线后再调用await()等待其他线程] 2. 所有 ...

随机推荐

  1. CentOS7.7下二进制部署MySQL多版本多实例实战

    第一章 需求说明 部署MySQL5.7的三个多实例环境(端口分别为3307,3308,3309) 部署MySQL5.6和8.0版本数据库实例((端口分别为3316和3326) 第二章 环境准备 1.虚 ...

  2. ADO.Net和Entity Framework的区别联系

    它们有以下几点区别:1,ADO.Net是开发人员自己select.update等写sql语句,来实现对数据库的增删改查等操作:采用EF进行开发操作数据库的时候,只需要操作对象,这样做使开发更方便,此时 ...

  3. Vue自定义指令 数据传递

    在项目开发过程中,难免会遇到各种功能需要使用Vue自定义指令--directive 去实现 .关于directive的使用方式这里就不做过多的介绍了,Vue官方文档中说的还是听明白的.今天讲讲在使用V ...

  4. Redis分布式锁的正确姿势

    1. 核心代码: import redis.clients.jedis.Jedis; import java.util.Collections; /** * @Author: qijigui * @C ...

  5. token认证和理解

    认知篇:https://blog.csdn.net/FYGu18/article/details/89345490 token失效篇认知:https://segmentfault.com/q/1010 ...

  6. auth权限逻辑

    下面本人为大家讲解一下如何实现auth权限, 第一步,新建Auth.php,复制下面的代码,把注释中的表都创建一下.把文件放到extend新建文件夹org放进去即可, <?php // +--- ...

  7. Makefile 中引用多个 include 路径

    LIB=-L/usr/informix/lib/c++ INC=-I/usr/informix/incl/c++ -I/opt/informix/incl/public default: main m ...

  8. Docker 部署 halo 启动时,MySql 连接不上

    原因 halo 是部署在 docker 容器内部的,而 MySql 是部署在"宿主机"上的,docker默认的网络模式是bridge,容器内127.0.0.1访问不到的,把网络模式 ...

  9. Python 3之bytes新特性

    转载: Python 3最重要的新特性大概要算是对文本和二进制数据作了更为清晰的区分. 文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示. Python 3不会以任意隐式的方 ...

  10. LightOJ 1287 Where to Run(期望)

    题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1287 题意:给定一个n个点的无向图(0到n-1),你开始在0.你开始遍历这个图 ...