多线程——工具类之Semaphore
一、Semaphore功能介绍
Semaphore类相当于线程计数器,在获取Semaphore对象时设定可以产生的线程总数(线程并不是Semaphore类生成的,它只是统计线程的数量),创建Semaphore类对象如下方法所示:
//创建一个Semaphore对象,Sync sync对象赋值为NonfairSync对象
Semaphore sp = new Semaphore(1); //创建一个Semaphore对象,Sync sync对象赋值为FairSync对象
Semaphore sp = new Semaphore(1,true);
在创建线程以前调用Semaphore类的acquire()方法来判断是否还可以创建线程,acquire()方法每调用一次当前可创建的线程总数减一,并且这个方法是一个阻塞式的方法,如果当前线程数量已经达到上限线程会被阻塞,当满足创建线程的条件时程序就会继续,在线程运行结束以后调用Semaphore类release()方法来释放占用的可创建线程的数量。
结论:Semaphore类可以控制并发情况下创建的线程总数
二、Semaphore类方法分解
如下是Semaphore类的构造方法:
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
如下是对NonfairSync类和FairSync类的源码,从代码看似乎两个类对tryAcquireShared(int acquires)方法的实现完全不同,其实它们的实现基本相同,NonfairSync类调用的父类的nonfairTryAcquireShared(acquires)方法,此方法的实现如下所示,对比来看区别在于FairSync类在方法入口调用了hasQueuedPredecessors()方法添加了if判断,hasQueuedPredecessors代码如下所示。
/**
* NonFair version
*/
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);
}
} /**
* Fair version
*/
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;
}
}
}
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1192457210091910933L;
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
}
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
1、acquire()/acquire(int)方法介绍
如下所示,acquire()方法调用的是父类的acquireSharedInterruptibly(int arg)方法,这个方法调用子类的tryAcquireShared(int arg)如果没有线程数达到上限时则执行doAcquireSharedInterruptibly(arg),如下所示这个方法里面有一个死循环,当可创建的线程数量满足参数arg时,跳出死循环,创建线程的代码继续。
结论:acquire()是一个阻塞式的方法,从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞,或者当前线程中断时抛出InterruptedException异常,中断阻塞。
。
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
} private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
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 >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
2、acquireUninterruptibly()/acquireUninterruptibly()方法介绍
这两个方法和acquire()的两个方法基本是一样的,唯一不同是,这两个调用的方法acquireShared(int)没有了当前线程是否中断的if判断并且当前这个方法不抛InterruptedException异常,所以在当前线程被中断时当前阻塞的方法不会中断。
结论:acquireUninterruptibly是一个阻塞式的方法,从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞。
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
三、样例演示
如下代码是一个简单的样例,运行下面代码,从打印信息的顺序就可以验证获取信号量的方法是一个阻塞时的,其它方法的功能验证,网友自己完成吧!
public class ThreadTest {
public static void main(String[] args) throws Exception {
semaphoreTest();
}
public static void semaphoreTest() throws InterruptedException {
final Semaphore semaphore = new Semaphore(1);
System.out.println("1");
semaphore.acquire();
Thread t1 = new Thread() {
@Override
public void run() {
try {
sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("释放");
semaphore.release();
}
};
t1.start();
semaphore.acquire();
System.out.println("2");
}
}
多线程——工具类之Semaphore的更多相关文章
- Java并发(十五):并发工具类——信号量Semaphore
先做总结: 1.Semaphore是什么? Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源. 把它比作是控制流量的红绿灯,比如XX马路要 ...
- Java多线程并发工具类-信号量Semaphore对象讲解
Java多线程并发工具类-Semaphore对象讲解 通过前面的学习,我们已经知道了Java多线程并发场景中使用比较多的两个工具类:做加法的CycliBarrier对象以及做减法的CountDownL ...
- 多线程工具类:CountDownLatch、CyclicBarrier、Semaphore、LockSupport
◆CountDownLatch◆ 假如有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以.比如你想要买套房子,但是呢你现在手上没有钱.你得等这个月工资发了.然后年终奖发了.然后朋友借你得钱 ...
- JUC——线程同步辅助工具类(Semaphore,CountDownLatch,CyclicBarrier)
锁的机制从整体的运行转态来讲核心就是:阻塞,解除阻塞,但是如果仅仅是这点功能,那么JUC并不能称为一个优秀的线程开发框架,然而是因为在juc里面提供了大量方便的同步工具辅助类. Semaphore信号 ...
- java中重要的多线程工具类
前言 之前学多线程的时候没有学习线程的同步工具类(辅助类).ps:当时觉得暂时用不上,认为是挺高深的知识点就没去管了.. 在前几天,朋友发了一篇比较好的Semaphore文章过来,然后在浏览博客的时候 ...
- 【Java并发工具类】Semaphore
前言 1965年,荷兰计算机科学家Dijkstra提出的信号量机制成为一种高效的进程同步机制.这之后的15年,信号量一直都是并发编程领域的终结者.1980年,管程被提出,成为继信号量之后的在并发编程领 ...
- Java多线程工具类之循环栅栏计数器
Java多线程下循环计数器 本文主要内容:CyclicBarrier(下文中凯哥就用cycBar来代替)定义介绍:举例说明:代码演示:从源码来看原理及总结:CyclicBarrier与CountDow ...
- Java多线程同步工具类之Semaphore
Semaphore信号量通常做为控制线程并发个数的工具来使用,它可以用来限制同时并发访问资源的线程个数. 一.Semaphore使用 下面我们通过一个简单的例子来看下Semaphore的具体使用,我们 ...
- j.u.c系列(10)---之并发工具类:Semaphore
写在前面 Semaphore是一个计数信号量,它的本质是一个"共享锁". 信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可:当信号量中有可用的许可 ...
随机推荐
- 使用simhash库来进行网页去重
首先感谢作者yanyiwu贡献的开源项目https://github.com/yanyiwu/simhash.在做项 目过程中,翻了一遍<这就是搜索引擎 核心技术详解>这本书的查重算法, ...
- 在Keil uv5里面添加STC元器件库,不影响其他元件
先到网上下载stc.CBD(http://download.csdn.net/detail/mao0514/9699117) 还有STC新系列单片机的头文件,宏晶的网站就有 1.在Keil/C51/I ...
- FusionCharts重写单系列图
/** * @Title:FusionChart.java * @Package:com.yhd.chart.model * @Description:封装FusionChart单系列图 * @aut ...
- 《实战Nginx》读书笔记--Nginx配置文件
先看下一份的Nginx 的配置 #user nobody nobody;#使用的用户和组 worker_processes 4;#工作进程的个数,一般等于CPU核数或者总核数的两倍 #error_lo ...
- 使用AspNetPager控件分页
页面后台写法 protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { BindData(); } } pro ...
- ajax交互数据简单拼装,数组成字符串
json2Form:function(json) { var str = ""; for(var p in json){ // 判断对象是否为数组 if(typeof json[p ...
- 【BZOJ2434】阿狸的打字机(AC自动机,树状数组)
[BZOJ2434]阿狸的打字机(AC自动机,树状数组) 先写个暴力: 每次打印出字符串后,就插入到\(Trie\)树中 搞完后直接搭\(AC\)自动机 看一看匹配是怎么样的: 每次沿着\(AC\)自 ...
- 【Luogu2711】小行星(网络流,最大流)
[Luogu2711]小行星(网络流,最大流) 题面 题目描述 星云中有n颗行星,每颗行星的位置是(x,y,z).每次可以消除一个面(即x,y或z坐标相等)的行星,但是由于时间有限,求消除这些行星的最 ...
- Luogu2973:[USACO10HOL]赶小猪
题面 Luogu Sol 设\(f[i]\)表示炸弹到\(i\)不爆炸的期望 高斯消元即可 另外,题目中的概率\(p/q\)实际上为\(1-p/q\) 还有,谁能告诉我不加\(EPS\),为什么会输出 ...
- 云计算之路-阿里云上:博客web服务器轮番CPU 100%
今天下午14:30左右开始,不知道怎么回事,博客站点负载均衡中的web服务器轮番CPU 100%.平时访问高峰5台服务器就能稳稳支撑,而今天发现CPU出现100%问题后就开始加服务器,结果到目前加到了 ...