在Java的并发包中,Semaphore类表示信号量。Semaphore内部主要通过AQS(AbstractQueuedSynchronizer)实现线程的管理。Semaphore有两个构造函数,参数permits表示许可数,它最后传递给了AQS的state值。线程在运行时首先获取许可,

如果成功,许可数就减1,线程运行,当线程运行结束就释放许可,许可数就加1。

如果许可数为0,则获取失败,线程位于AQS的等待队列中,它会被其它释放许可的线程唤醒。在创建Semaphore对象的时候还可以指定它的公平性。

一般常用非公平的信号量,非公平信号量是指在获取许可时先尝试获取许可,

而不必关心是否已有需要获取许可的线程位于等待队列中,如果获取失败,才会入列。

而公平的信号量在获取许可时首先要查看等待队列中是否已有线程,如果有则入列。

先看测试案例:

package com.cxy.cyclicBarrier;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit; /**
* Created by Administrator on 2017/4/10.
*/
public class CxyDemo {
private final static int threadCount = ; public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(); for (int i = ; i < threadCount; i++) {
System.out.println(i+"----------------------");
final int threadNum = i;
exec.execute(() -> {
try {
if (semaphore.tryAcquire(, TimeUnit.MILLISECONDS)) { // 尝试获取一个许可
test(threadNum);
semaphore.release(); // 释放一个许可
}
} catch (Exception e) {
// log.error("exception" , e);
System.out.println(e);
}
});
}
exec.shutdown();
} private static void test(int threadNum) throws Exception {
// log.info("{}" , threadNum);
System.out.println("a"+threadNum);
Thread.sleep();
} }

执行结果:

源码分析:

构造方法:

 public Semaphore(int permits) {
sync = new NonfairSync(permits);
} /**
* Creates a {@code Semaphore} with the given number of
* permits and the given fairness setting.
*
* @param permits the initial number of permits available.
* This value may be negative, in which case releases
* must occur before any acquires will be granted.
* @param fair {@code true} if this semaphore will guarantee
* first-in first-out granting of permits under contention,
* else {@code false}
*/
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

第一个构造方法:是允许的信号量

第二个,里面传入的boolean参数,采用的是公平锁还是分公平锁

tryAcquire源码
 public boolean tryAcquire(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(, unit.toNanos(timeout));
} public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquireShared(arg) >= ||
doAcquireSharedNanos(arg, nanosTimeout);
} private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= ) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return true;
}
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
release源码
    public void release() {
sync.releaseShared();
} public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
} private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, ))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == &&
!compareAndSetWaitStatus(h, , Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}

JUC包下Semaphore学习笔记的更多相关文章

  1. JUC包下CyclicBarrier学习笔记

    CyclicBarrier,一个同步辅助类,在API中是这么介绍的: 它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序中,这 ...

  2. JUC包下CountDownLatch学习笔记

    CountDownLatch的作用是能使用多个线程进来之后,且线程任务执行完毕之后,才执行, 闭锁(Latch):一种同步方法,可以延迟线程的进度直到线程到达某个终点状态.通俗的讲就是,一个闭锁相当于 ...

  3. Linux下iptables学习笔记

    Linux下iptables学习笔记 在Centos7版本之后,防火墙应用已经由从前的iptables转变为firewall这款应用了.但是,当今绝大多数的Linux版本(特别是企业中)还是使用的6. ...

  4. YOLO---Darknet下的学习笔记 V190319

    YOLO---Darknet下的学习笔记 @WP 20190319 很久没有用YOlO算法了,今天又拿过来玩玩.折腾半天,才好运行通的,随手记一下: 一是,终端下的使用.二是,python接口的使用. ...

  5. YOLO---Darknet下的学习笔记

    YOLO.V3-Darknet下的学习笔记 @wp20180927 [目录] 一. 安装Darknet(仅CPU下) 2 1.1在CPU下安装Darknet方式 2 1.2在GPU下安装Darknet ...

  6. JUC.Lock(锁机制)学习笔记[附详细源码解析]

    锁机制学习笔记 目录: CAS的意义 锁的一些基本原理 ReentrantLock的相关代码结构 两个重要的状态 I.AQS的state(int类型,32位) II.Node的waitStatus 获 ...

  7. 20135202闫佳歆--week5 系统调用(下)--学习笔记

    此为个人笔记存档 week 5 系统调用(下) 一.给MenuOS增加time和time-asm命令 这里老师示范的时候是已经做好的了: rm menu -rf 强制删除 git clone http ...

  8. juc包:使用 juc 包下的显式 Lock 实现线程间通信

    一.前置知识 线程间通信三要素: 多线程+判断+操作+通知+资源类. 上面的五个要素,其他三个要素就是普通的多线程程序问题,那么通信就需要线程间的互相通知,往往伴随着何时通信的判断逻辑. 在 java ...

  9. 【Java多线程】JUC包下的工具类CountDownLatch、CyclicBarrier和Semaphore

    前言 JUC中为了满足在并发编程中不同的需求,提供了几个工具类供我们使用,分别是CountDownLatch.CyclicBarrier和Semaphore,其原理都是使用了AQS来实现,下面分别进行 ...

随机推荐

  1. Windows 环境下于虚拟环境中源码安装 cx_oracle

    安装前提条件: (1).安装 instantclient-basic-nt (2).安装 instantclient-sdk-nt (3).安装 Microsoft Visual C++ Compil ...

  2. shell 别名alias

    在这说下 shell   命令 alias 别名   看个人爱好 设置. 直接执行命令  显示当前所有别名 alias  别名='新的别名'  该命令在当窗口关闭以后 会失效  想要永久生效  需要在 ...

  3. 8.INSERT INTO 语句 UPDATE 语句

    1. INSERT INTO 语句 INSERT INTO 语句用于向表格中插入新的行. 语法 INSERT INTO 表名称 VALUES (值1, 值2,....) INSERT INTO Per ...

  4. CF407B Long Path

    好玩的题. 首先我们(看一下题解之后)发现当你第一次走到了一个点的时候,那么它之前的所有点一定都访问过了偶数次. 假设我们第一次走到了一个点$i$,那么$i - 1$一定访问了偶数次,那么第一次走$i ...

  5. 方向ajax(http long request实现实时通信)

    现在我们就要通过这种方法来实现实时通信,先说一下原理: 客户端发起一个ajax长链接查询,然后服务端就开始执行代码,主要是检查某个文件是否被更新,如果没有,睡一会(sleep),醒来接着检查 如果客户 ...

  6. Controller级别的异常处理过滤器IExceptionFilter

    1,系统自带的HandleErrorAttribute类继承自IExceptionFilter,是MVC的默认实现. 同时设置web.config <system.web> <cus ...

  7. EasyUI combobox实现下拉框多选遇坑记录

    场景一: 多选正常从第二个选项增加逗号,我选第一个的时候就冒出一个逗号 解决方案一: 这是因为当前的下拉框的值可能为undefined,需要手动清空一下 $("#id").comb ...

  8. c# 简单委托例子

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. JS Img对象获取图片高度宽度(兼容Chrome)

    一般获取图片高度宽度的写法: var img = new Image();img.src = imgsrc;var imgWH = CalcImgTiple(img.width, img.height ...

  10. duilib入门简明教程 -- 第一个程序 Hello World(3)

    小伙伴们有点迫不及待了么,来看一看Hello World吧: 新建一个空的win32项目,新建一个main.cpp文件,将以下代码复制进去: #include <windows.h> #i ...