JAVA多线程提高九:Semaphere同步工具
java 中Semaphere可类比操作系统信号量,硬件资源如IO、内存、磁盘等都是有固定量的,多个程序需要竞争这些资源,没有资源就需要被挂起。
一、类和方法摘要
构造函数:
public Semaphore(int permits):创建具有给定的许可数和非公平的公平设置的 Semaphore。
-参数 :
permits - 初始的可用许可数目。此值可能为负数,在这种情况下,必须在授予任何获取前进行释放。
public Semaphore(int permits, boolean fair):创建具有给定的许可数和给定的公平设置的 Semaphore。
-参数:
permits - 初始的可用许可数目。此值可能为负数,在这种情况下,必须在授予任何获取前进行释放。
fair - 如果此信号量保证在争用时按先进先出的顺序授予许可,则为 true;否则为 false。
常用方法:
void acquire():从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。
void release():释放一个许可,将其返回给信号量。
int availablePermits():返回此信号量中当前可用的许可数。
boolean hasQueuedThreads():查询是否有线程正在等待获取。
二、使用技巧
将信号量初始化为 1,使得它在使用时最多只有一个可用的许可,从而可用作一个相互排斥的锁。这通常也称为二进制信号量,因为它只能有两种状态:一个可用的许可,或零个可用的许可。按此方式使用时,二进制信号量具有某种属性(与很多 Lock 实现不同),即可以由线程释放“锁”,而不是由所有者(因为信号量没有所有权的概念)。在某些专门的上下文(如死锁恢复)中这会很有用。
三、对比线程池
线程池控制的是线程数量,而信号量控制的是并发数量,虽然说看起来一样,但两者还是有区别的。
信号量类似于锁机制,信号量的调用,当达到数量后,线程还是存在的,只是被挂起了而已。而线程池,同时执行的线程数量是固定的,超过了数量的只能等待。
代码示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore; public class SemaphoreTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final Semaphore sp = new Semaphore(3);
for(int i=0;i<10;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
sp.acquire();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() +
"进入,当前已有" + (3-sp.availablePermits()) + "个并发");
try {
Thread.sleep((long)(Math.random()*10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() +
"即将离开");
sp.release();
//下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
System.out.println("线程" + Thread.currentThread().getName() +
"已离开,当前已有" + (3-sp.availablePermits()) + "个并发");
}
};
service.execute(runnable);
}
} }
输出:
线程pool-1-thread-1进入,当前已有3个并发
线程pool-1-thread-3进入,当前已有3个并发
线程pool-1-thread-2进入,当前已有3个并发
线程pool-1-thread-1即将离开
线程pool-1-thread-1已离开,当前已有2个并发
线程pool-1-thread-4进入,当前已有3个并发
线程pool-1-thread-3即将离开
线程pool-1-thread-3已离开,当前已有2个并发
线程pool-1-thread-5进入,当前已有3个并发
线程pool-1-thread-4即将离开
线程pool-1-thread-4已离开,当前已有2个并发
线程pool-1-thread-6进入,当前已有3个并发
线程pool-1-thread-2即将离开
线程pool-1-thread-2已离开,当前已有2个并发
线程pool-1-thread-7进入,当前已有3个并发
线程pool-1-thread-7即将离开
线程pool-1-thread-7已离开,当前已有2个并发
线程pool-1-thread-8进入,当前已有3个并发
线程pool-1-thread-5即将离开
线程pool-1-thread-5已离开,当前已有3个并发
线程pool-1-thread-9进入,当前已有3个并发
线程pool-1-thread-6即将离开
线程pool-1-thread-6已离开,当前已有2个并发
线程pool-1-thread-10进入,当前已有3个并发
线程pool-1-thread-8即将离开
线程pool-1-thread-8已离开,当前已有2个并发
线程pool-1-thread-10即将离开
线程pool-1-thread-10已离开,当前已有1个并发
线程pool-1-thread-9即将离开
线程pool-1-thread-9已离开,当前已有0个并发
可以同时有3个线程执行sp.acquire()到sp.release()之间的代码。
参考资料:
<<Java多线程与并发库高级应用>> 张孝祥 视频
JAVA多线程提高九:Semaphere同步工具的更多相关文章
- JAVA多线程提高十四:同步工具Exchanger
Exchanger可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchange 方法,与伙伴线程进行匹配,并且在返回时接收其伙伴的对象.Exchanger 可能被视 ...
- java多线程系列9 高级同步工具(3) CyclicBarrier
CyclicBarrier 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point) 然后一再执行 public class CyclicBar ...
- java多线程系列7 高级同步工具(1)信号量Semaphore
Semaphore叫做信号量 可以控制某个资源可被同时访问的个数, acquire() 获取一个许可,得到许可才能执行后面的代码,如果没有就等待. release() 释放一个许可. 当信号量的只允许 ...
- java多线程系列8 高级同步工具(2)CountDownLatch
CountDownLatch,计数器的初始值为线程的数量.每当一个线程完成了自己的任务后, 计数器的值就会减1.当计数器值到达0时,它表示所有的线程已经完成了任务, 然后在闭锁上等待的线程就可以恢复执 ...
- java多线程系列(九)---ArrayBlockingQueue源码分析
java多线程系列(九)---ArrayBlockingQueue源码分析 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 j ...
- Java多线程之线程的同步
Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...
- Java多线程——线程之间的同步
Java多线程——线程之间的同步 摘要:本文主要学习多线程之间是如何同步的,如何使用volatile关键字,如何使用synchronized修饰的同步代码块和同步方法解决线程安全问题. 部分内容来自以 ...
- JAVA多线程提高十:同步工具CyclicBarrier与CountDownLatch
今天继续学习其它的同步工具:CyclicBarrier与CountDownLatch 一.CyclicBarrier CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公 ...
- Java多线程编程(4)--线程同步机制
一.锁 1.锁的概念 线程安全问题的产生是因为多个线程并发访问共享数据造成的,如果能将多个线程对共享数据的并发访问改为串行访问,即一个共享数据同一时刻只能被一个线程访问,就可以避免线程安全问题.锁 ...
随机推荐
- hdu 1241--入门DFS
Oil Deposits Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tot ...
- JavaScript DOM编程艺术学习笔记-第一章JavaScript简史
一,JavaScript的起源 JavaScript是Netscape与Sun公司合作开发,它是一种脚本语言,通常只能通过Web浏览器去完成一些操作.JavaScript为程序员提供了一些操控Web浏 ...
- prototype.js中Function.prototype.bind方法浅解
prototype.js中的Function.prototype.bind方法: Function.prototype.bind = function() { var __method = this; ...
- ORACLE公司传奇历史
ORACLE公司传奇 ORACLE公司之起源 很难想象,ORACLE 公司的这一段传奇居然要从 IBM 公司开始. 1970年的6月,IBM 公司的研究员埃德加·考特 (Edgar Frank Cod ...
- equals()和hashcode()详解
转载自http://www.cnblogs.com/Qian123/p/5703507.html java.lang.Object类中有两个非常重要的方法: public boolean equa ...
- nginx 几个常用的标准模块介绍
ngx_http_ssl_module(https) 1:指明是否启用的虚拟主机的ssl功能 ssl on | off; 2:指明虚拟主机使用的证书文件 ssl_certificate /usr/lo ...
- TClientDataSet[5]: 读取数据
本例用到: TClientDataSet.Fields[]; { 字段集合; 它比 FieldList 有更多功能, 如可获取嵌套字段 } TClientDataSet.FieldL ...
- 第163天:js面向对象-对象创建方式总结
面向对象-对象创建方式总结 1. 创建对象的方式,json方式 推荐使用的场合: 作为函数的参数,临时只用一次的场景.比如设置函数原型对象. var obj = {}; //对象有自己的 属性 和 行 ...
- uoj54-bzoj3434-时空穿梭
题意 在一个 \(n\) 维空间中,求一个点可以用一个 \(n\) 维向量 \((x_1,x_2,\dots x_n)\) 表示.现在要选出 \(c\) 个点,有三个限制: 设 \(x_i\) 表示任 ...
- 51nod 1682 中位数计数(差分统计)
中位数定义为所有值从小到大排序后排在正中间的那个数,如果值有偶数个,通常取最中间的两个数值的平均数作为中位数. 现在有n个数,每个数都是独一无二的,求出每个数在多少个包含其的区间中是中位数. 首先,显 ...