【Java并发编程五】信号量
一、概述
技术信号量用来控制能够同时访问某特定资源的活动的数量,或者同时执行某一给定操作的数据。计数信号量可以用来实现资源池或者给一个容器限定边界。
信号量维护了一个许可集,许可的初始量通过构造函数传递给Semaphore。活动能够获取许可,并在使用之后释放许可,如果没有可用的许可,acquire方法会被阻塞,直到有可用的为止。每个release方法添加一个许可,从而可能释放一个正在阻塞的获取者。
计算信号量的一种退化形式是二元信号量:一个计数初始值为1的Semaphore,二元信号量可用作互斥锁。
二、应用场景
信号量可用来实现资源池,比如数据库连接池。示例代码如下:
class Pool
{
private static final int MAX_AVAILABLE = 100;
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true); public Object getItem() throws InterruptedException
{
available.acquire();
return getNextAvailableItem();
} public void putItem(Object x)
{
if (markAsUnused(x))
available.release();
}
MyResource resource1=new MyResource("资源1");
MyResource resource2=new MyResource("资源2");
MyResource resource3=new MyResource("资源3");
protected MyResource[] items = new MyResource[]{resource1,resource2,resource3};
protected boolean[] used = new boolean[MAX_AVAILABLE];
protected synchronized Object getNextAvailableItem()
{
for (int i = 0; i < MAX_AVAILABLE; ++i)
{
if (!used[i])
{
used[i] = true;
return items[i];
}
}
return null; // not reached
} protected synchronized boolean markAsUnused(Object item)
{
for (int i = 0; i < MAX_AVAILABLE; ++i)
{
if (item == items[i])
{
if (used[i])
{
used[i] = false;
return true;
}
else
return false;
}
}
return false;
}
}
class MyResource
{
String resourceName;
public MyResource(String resourceName)
{
this.resourceName=resourceName;
}
}
三、使用方法
构造函数:
Semaphore(int permits):创建具有给定许可数和非公平设置的Semaphore
Semaphore(int permits,boolean fair):此类的构造方法可选地接受一个公平 参数。当设置为 false 时,此类不对线程获取许可的顺序做任何保证。特别地,闯入是允许的,也就是说可以在已经等待的线程前为调用 acquire()
的线程分配一个许可,从逻辑上说,就是新线程将自己置于等待线程队列的头部。当公平设置为 true 时,信号量保证对于任何调用获取
方法的线程而言,都按照处理它们调用这些方法的顺序(即先进先出;FIFO)来选择线程、获得许可。注意,FIFO 排序必然应用到这些方法内的指定内部执行点。所以,可能某个线程先于另一个线程调用了 acquire
,但是却在该线程之后到达排序点,并且从方法返回时也类似。
Semaphore还提供一些其他方法:
- int availablePermits() :返回此信号量中当前可用的许可证数。
- int getQueueLength():返回正在等待获取许可证的线程数。
- boolean hasQueuedThreads() :是否有线程正在等待获取许可证。
- void reducePermits(int reduction) :减少reduction个许可证。是个protected方法。
- Collection getQueuedThreads() :返回所有等待获取许可证的线程集合。是个protected方法。
示例代码如下:
public class SemaphoreTest
{ public static void main(String[] args)
{
Semaphore semaphore=new Semaphore(3);
for(int i=0;i<5;i++)
{
MyThread myThread=new MyThread("线程"+i, semaphore);
myThread.start();
}
}
static class MyThread extends Thread
{
String name;
Semaphore semaphore;
public MyThread(String name,Semaphore semaphore)
{
this.name=name;
this.semaphore=semaphore;
}
@Override
public void run()
{
try
{
semaphore.acquire();
System.out.println(name+"获取信号量,开始工作...");
Thread.sleep(3000);
System.out.println(name+"工作结束"+",正在等待获取许可证的线程数:"+semaphore.getQueueLength());
}
catch (InterruptedException e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
}
finally
{
semaphore.release();
}
}
}
}
执行结果如下:
四、参考资料
1、Java并发编程实践
【Java并发编程五】信号量的更多相关文章
- Java并发编程--5.信号量和障碍器
Semaphore信号量 简介 它本质上是一个共享锁,限制访问公共资源的线程数目,它也被称为计数信号量acquire()许可一个线程, Semaphore – 1; 没有可用的许可时,Semaphor ...
- [java并发编程]基于信号量semaphore实现限流器
目录 一.什么是信号量 二.信号量类Semaphore 三.实现限流器 欢迎关注我的博客,更多精品知识合集 一.什么是信号量 "信号量"在编程术语中使用单词semaphore,那什 ...
- Java并发编程 (五) 线程安全性
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.安全发布对象-发布与逸出 1.发布与逸出定义 发布对象 : 使一个对象能够被当前范围之外的代码所使用 ...
- [Java并发编程(五)] Java volatile 的实现原理
[Java并发编程(五)] Java volatile 的实现原理 简介 在多线程并发编程中 synchronized 和 volatile 都扮演着重要的角色,volatile 是轻量级的 sync ...
- Java并发编程原理与实战五:创建线程的多种方式
一.继承Thread类 public class Demo1 extends Thread { public Demo1(String name) { super(name); } @Override ...
- java并发编程笔记(五)——线程安全策略
java并发编程笔记(五)--线程安全策略 不可变得对象 不可变对象需要满足的条件 对象创建以后其状态就不能修改 对象所有的域都是final类型 对象是正确创建的(在对象创建期间,this引用没有逸出 ...
- 转: 【Java并发编程】之十八:第五篇中volatile意外问题的正确分析解答(含代码)
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17382679 在<Java并发编程学习笔记之五:volatile变量修饰符-意料之外 ...
- Java并发编程(五)JVM指令重排
我是不是学了一门假的java...... 引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序:在特定情况下,指令重排将会给我们的程序带来不确定的结果.. ...
- Java并发编程原理与实战二十五:ThreadLocal线程局部变量的使用和原理
1.什么是ThreadLocal ThreadLocal顾名思义是线程局部变量.这种变量和普通的变量不同,这种变量在每个线程中通过get和set方法访问, 每个线程有自己独立的变量副本.线程局部变量不 ...
随机推荐
- SQL数据查询之——嵌套查询
一.概念描述 在SQL语言中,一个 SELECT-FROM-WHERE 语句称为一个查询块.将一个查询块嵌套在另一个查询块的 WHERE 子句或 HAVING 短语的条件中的查询称为 嵌套查询.例如: ...
- Windows 2008安装Oracle10g提示操作系统版本检查未通过
原文链接:http://www.cnblogs.com/emanlee/archive/2012/12/18/2824147.html 因开发环境需要,在Windows Server 2008 R2 ...
- tRNAscan-SE 预测tRNA基因
tRNAscan-SE 软件可以根据输入的基因组序列,预测对应的tRNA的基因 在线的tRNAscan-SE的链接如下:http://lowelab.ucsc.edu/tRNAscan-SE/ 如下图 ...
- IntelliJ IDEA Default Keymap
Alt+回车 导入包,自动修正Ctrl+N 查找类Ctrl+Shift+N 查找文件Ctrl+Alt+L 格式化代码Ctrl+Alt+O 优化导入的类和包Alt+Insert 生成代码(如get ...
- iOS: hide UITextField Cursor
Simply subclass UITextField and override caretRectForPosition (继承 UITextField 并且重写 [UITextField care ...
- php无限分类二
1.读取数据数据 /** * 所有分类数据 * */ public function categoryData(){ $order = 'id,sort asc'; $res = $this-> ...
- Hibernate的七种映射关系之基本映射
说到关系,在这个世界无处不在,我们必须以某个关系的节点存在在这个世界网中.比如父子关系,师生关系,上下属关系甚至是危险关系.数据也是一样的,它的存在必为某其他节点做准备. Hibernate有七种映射 ...
- spring测试junit事务管理及spring面向接口注入和实现类单独注入(无实现接口),实现类实现接口而实现类单独注入否则会报错。
1.根据日志分析,spring junit默认是自动回滚,不对数据库做任何的操作. 18:16:57.648 [main] DEBUG o.s.j.d.DataSourceTransactionMan ...
- ActiveMQ的消息存储方式
1. 队列存储 采取先进先出模式,同一时间,消息只会发送给某一个消费者,只有当该消息被消费并告知已收到时,它才能在代理的存储中被删除. 对于持久性订阅来说,每一个消费者都会 ...
- myeclipse安装jad反编译插件
有时候想深入底层看jar包封装的源代码,但是打不开.这就需要配置反编译插件: 1:准备原材料 jad.exe + net.sf.jadclipse_3.3.0.jar 下载目录: jad.exe : ...