java Concurrent包学习笔记(五):Semaphore
一、Semaphore 是什么
信号量Semaphore是一个并发工具类,用来控制可同时并发的线程数,其内部维护了一组虚拟许可,构造函数初始化的时候可以指定许可的总数量
每次线程执行操作时先通过acquire方法获得许可,线程获得许可后Semaphore 的许可数量会减1,执行完毕再通过release方法释放许可,emaphore 的许可数量会加1。如果无可用许可,那么acquire方法将一直阻塞,直到其它线程释放许可。
主要方法:
- Semaphore(int permits): 构造方法,创建具有给定许可数的计数信号量并设置为非公平信号量。
- Semaphore(int permits,boolean fair): 构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量。
- void acquire(): 从此信号量获取一个许可,如果没有获取到许可线程将一直阻塞。
- void acquire(int n): 从此信号量获取给定数目许可,在提供这些许可前一直将线程阻塞。
- void release(): 释放一个许可,将其返回给信号量。就如同车开走返回一个车位。
- void release(int n): 释放n个许可。
- int availablePermits():当前可用的许可数
二、Semaphore 和线程池的区别
- 线程池:用来控制实际工作的线程数量,通过线程复用的方式来减小内存开销。线程池可同时工作的线程数量是一定的,超过该数量的线程需进入线程队列等待,直到有可用的工作线程来执行任务。
- Semaphore: 你创建了多少线程,实际就会有多少线程进行执行,只是可同时执行的线程数量会受到限制。但使用线程池,不管你创建多少线程,实际可执行的线程数是一定的。
示例程序:
package semaphore.demo; import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore; /**
* @author boshen
* @date 2018/12/20
*/
public class SemaphoreTest1 {
/**
* 用线程池来控制工作线程
*/
private static void testThreadPoll(){
ExecutorService executorService = Executors.newFixedThreadPool();
for(int i = ;i< ;i++)
executorService.submit(new Runnable() {
public void run() {
try {
String name = UUID.randomUUID().toString().substring(,);
System.out.println("学生:"+name +" 开始工作,线程号为:"+Thread.currentThread().getName());
Thread.sleep();
System.out.println("学生:"+name +" 完成工作,线程号为:"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
executorService.shutdown();
} /**
* 用Semaphore来控制工作线程
*/
private static void testSemaphore(){
final Semaphore semaphore = new Semaphore();
for(int i=;i<;i++){
Thread thread = new Thread(new Runnable() {
public void run() {
try {
semaphore.acquire();
String name = UUID.randomUUID().toString().substring(,);
System.out.println("学生:"+name +" 开始工作,线程号为:"+Thread.currentThread().getName());
Thread.sleep();
System.out.println("学生:"+name +" 完成工作,线程号为:"+Thread.currentThread().getName());
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}
} public static void main(String[] args){
System.out.println("以下是testThreadPoll输出的结果============================================");
testThreadPoll();
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("以下是testSemaphore输出的结果============================================");
testSemaphore();
}
}
以下是testThreadPoll输出的结果============================================
学生:14fd- 开始工作,线程号为:pool--thread-
学生:6bc6- 开始工作,线程号为:pool--thread-
学生:6bc6- 完成工作,线程号为:pool--thread-
学生:6a3b- 开始工作,线程号为:pool--thread-
学生:14fd- 完成工作,线程号为:pool--thread-
学生:9e7b- 开始工作,线程号为:pool--thread-
学生:6a3b- 完成工作,线程号为:pool--thread-
学生:2ed3- 开始工作,线程号为:pool--thread-
学生:9e7b- 完成工作,线程号为:pool--thread-
学生:2ed3- 完成工作,线程号为:pool--thread-
以下是testSemaphore输出的结果============================================
学生:- 开始工作,线程号为:Thread-
学生:99e9- 开始工作,线程号为:Thread-
学生:99e9- 完成工作,线程号为:Thread-
学生:- 完成工作,线程号为:Thread-
学生:b9a5- 开始工作,线程号为:Thread-
学生:058d- 开始工作,线程号为:Thread-
学生:b9a5- 完成工作,线程号为:Thread-
学生:7f6a-c 开始工作,线程号为:Thread-
学生:058d- 完成工作,线程号为:Thread-
学生:7f6a-c 完成工作,线程号为:Thread-
由以上结果可知当使用前线池的时候,同时只有2个线程执行工作,线程号只会有1和2,线程会进行复用;Semaphore虽然也只有2个线程能同时工作,但是线程号是0、1、2、3、4,也就是5个线程都执行了,只不过同一时刻有三个线程阻塞了而已。
三、Semaphore 公平信号量和非公平信号量
示例:
package semaphore.demo; import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore; /**
* @author boshen
* @date 2018/12/20
*/
public class SemaphoreTest2 {
/**
* 公平信号量
*/
private static void testFairSemaphore(){
final Semaphore semaphore1 = new Semaphore(,true);
for(int i=;i<;i++){
Thread thread = new Thread(new Runnable() {
public void run() {
try {
String name = UUID.randomUUID().toString().substring(,);
System.out.println("学生:"+name +" 开始工作,线程号为:"+Thread.currentThread().getName());
semaphore1.acquire();
Thread.sleep();
System.out.println("学生:"+name +" 完成工作,线程号为:"+Thread.currentThread().getName());
semaphore1.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}
} /**
* 非公平信号量
*/
private static void testUnFairSemaphore(){
final Semaphore semaphore2 = new Semaphore();
for(int i=;i<;i++){
final Thread thread = new Thread(new Runnable() {
public void run() {
try {
String name = UUID.randomUUID().toString().substring(,);
System.out.println("学生:"+name +" 开始工作,线程号为:"+Thread.currentThread().getName());
semaphore2.acquire();
Thread.sleep();
System.out.println("学生:"+name +" 完成工作,线程号为:"+Thread.currentThread().getName());
semaphore2.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}
} public static void main(String[] args){
System.out.println("以下是testFairSemaphore输出的结果============================================");
testFairSemaphore();
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("以下是testUnFairSemaphore输出的结果============================================");
testUnFairSemaphore();
}
}
以下是testFairSemaphore输出的结果============================================
学生:81f2- 开始工作,线程号为:Thread-
学生:-d 开始工作,线程号为:Thread-
学生:e212-a 开始工作,线程号为:Thread-
学生:f059-d 开始工作,线程号为:Thread-
学生:9ece- 开始工作,线程号为:Thread-
学生:81f2- 完成工作,线程号为:Thread-
学生:e212-a 完成工作,线程号为:Thread-
学生:-d 完成工作,线程号为:Thread-
学生:f059-d 完成工作,线程号为:Thread-
学生:9ece- 完成工作,线程号为:Thread-
以下是testUnFairSemaphore输出的结果============================================
学生:- 开始工作,线程号为:Thread-
学生:- 开始工作,线程号为:Thread-
学生:e920- 开始工作,线程号为:Thread-
学生:be7a-f 开始工作,线程号为:Thread-
学生:e4fc-b 开始工作,线程号为:Thread-
学生:- 完成工作,线程号为:Thread-
学生:e920- 完成工作,线程号为:Thread-
学生:- 完成工作,线程号为:Thread-
学生:e4fc-b 完成工作,线程号为:Thread-
学生:be7a-f 完成工作,线程号为:Thread-
公平信号量的效果:哪信线程首先调用Semaphore.acquire(),哪个线程优先获得许可,首先启动的线程优先获取许可(不是100%,只是增加了概率)
非公平信号量的效果:是与线程的启动顺序与调用Semaphore.acquire()顺序无关,也就是说先启动的线程并不一定先获得许可。
java Concurrent包学习笔记(五):Semaphore的更多相关文章
- java Concurrent包学习笔记(一):ExecutorService
一.介绍 ExecutorService是java.util.concurrent包中的一个线程池实现接口.其有两个实现类: 1)ThreadPoolExecutor:普通线程池通过配置线程池大小,能 ...
- java Concurrent包学习笔记(四):BlockingQueue
一.BlockingQueue概述 1.阻塞的含义 BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞.被阻塞的情况主要有如下两种: ,当一个线程对 ...
- java Concurrent包学习笔记(三):ReentrantLock
一.可重入性的理解 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入的,两者关于这个的区别不大.两者都是同一个线程每进入一次,锁 ...
- java Concurrent包学习笔记(六):Exchanger
一.概述 Exchanger 是一个用于线程间协作的工具类,Exchanger用于进行线程间的数据交换,它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据.这两个线程通过exchange 方法 ...
- java Concurrent包学习笔记(二):CountDownLatch和CyclicBarrier
一.CountDownLatch CountDownLatch一个线程同步的工具,是的一个或者多个线程等待其他线程操作完成之后再执行. CountDownLatch通过一个给定的数值count来进行初 ...
- java Concurrent包学习笔记(七):ConcurrentHashMap
(注意:以下讲解的ConcurrentHashMap是jdk 1.8的) 一.ConcurrentHashMap的数据结构 ConcurrentHashMap在1.8中的实现,相比于1.7的版本基本上 ...
- java之jvm学习笔记五(实践写自己的类装载器)
java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...
- java.util.concurrent包学习笔记(一)Executor框架
类图: 其实从类图我们能发现concurrent包(除去java.util.concurrent.atomic 和 java.util.concurrent.locks)中的内容并没有特别多,大概分为 ...
- java package 包 学习笔记
编译命令示例: javac -d . Main.java 注:带参数-d自动建立文件目录, 只使用javac 则需要手工创建目录 把 class文件打包 jar命令 jar cvf T.jar *; ...
随机推荐
- 上海大都会赛 I Matrix Game(最大流)
At the start of the matrix game, we have an N x M matrix. Each grid has some balls.The grid in (i,j) ...
- SQL Server2005/2008 作业执行失败的解决办法
数据库:SQL Server 2005/2008,运行环境:Windows Server 2008 在数据库里的所有作业都执行失败,包括自动执行和手动执行.在事件查看器里看到的错误报告如下: 该 作 ...
- 序列化_Transient
要实际的操作一下Serialize的代码Demo, 加深理解(某投行很喜欢问这个问题):transient关键字虽然目前还没有人面试过我,但是也是个考点
- VS2013中Nuget程序包管理器控制台使用入门(一)-准备环境(原创)
准备环境: 1.打开VS2013IDE集成开发环境. 2.新建一个Asp.net Mvc的项目,比如命名为:MvcApplication1 3.打开 菜单"工具"->&quo ...
- 用js实现回车登录而不用点击登录按钮
在你的登录jsp里面,添加一个js <script> function on_return(){ //on_return这是方法名 if(window.event.keyCode == 1 ...
- (转)Eclipse中需要查看某个类的源码,直接按住Ctrl 然后点击想要查看的类或则方法
文章转自:http://blog.sina.com.cn/s/blog_52f623240102vpcr.html 在Eclipse中需要查看某个类的源码,直接按住Ctrl 然后点击想要查看的 ...
- win7系统 无线上网卡 共享网络,设置成wifi热点
给家人买了一个新的智能手机,用的移动神州行套餐,没有开通3G,想更新一些应用软件,于是想到能不能用电脑上的无线上网卡. 在网上找到了一方法,试了一下,还真是可以. 步骤如下: 用无线上网卡拨号上网,并 ...
- PAT 1085 PAT单位排行(25)(映射、集合训练)
1085 PAT单位排行(25 分) 每次 PAT 考试结束后,考试中心都会发布一个考生单位排行榜.本题就请你实现这个功能. 输入格式: 输入第一行给出一个正整数 N(≤105),即考生人数.随 ...
- hdu 1198 (并查集 or dfs) Farm Irrigation
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1198 有题目图11种土地块,块中的绿色线条为土地块中修好的水渠,现在一片土地由上述的各种土地块组成,需要浇 ...
- js 闭包 弊端
闭包有许多有趣的用途,Javascript的两个特征使它这么有趣:1. function是一个对象,它跟数组,Object一样,地位平等.2. Javascript变量作用域范围.<Javasc ...