多线程编程(一)-Semaphore(信号量)的使用
- Semaphore的介绍
单词Semaphore的中文含义就是信号、信号系统的意思,此类的主要作用就是限制线程并发的数量。
举个例子,一个屋子里有10个人,但只有一个窄门可以出去,这个窄门一次最多只能通过一人,这样就限制了同时出门的人数,同理也就是限制了线程并发的数量,这也就是Semaphore类要达到的目的。
- 类Semaphore的同步性
多线程中的同步就是多个线程排队去执行任务,一个一个执行,不会有线程安全的问题。
构造函数参数permits是许可的意思,代表同一时间内,最多允许多少个线程同时执行acquire()和release()之间的代码。
无参方法acquire()的作用是默认使用1个许可。
package com.wjg.unit1; import java.util.concurrent.Semaphore; public class Service {
private Semaphore semaphore = new Semaphore(1);
public void testMethod(){
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+" begin timer="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+" end timer="+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
} }
} //运行类
package com.wjg.unit1; public class Run {
public static void main(String[] args) {
Service service = new Service();
Run run = new Run();
ThreadA a = run.new ThreadA(service);
a.setName("a");
a.start(); ThreadB b = run.new ThreadB(service);
b.setName("b");
b.start(); ThreadC c = run.new ThreadC(service);
c.setName("c");
c.start(); } public class ThreadA extends Thread { private Service service; public ThreadA(Service service) {
super();
this.service = service;
} @Override
public void run() {
service.testMethod();
}
} public class ThreadB extends Thread { private Service service; public ThreadB(Service service) {
super();
this.service = service;
} @Override
public void run() {
service.testMethod();
}
} public class ThreadC extends Thread { private Service service; public ThreadC(Service service) {
super();
this.service = service;
} @Override
public void run() {
service.testMethod();
}
}
} 运行结果:
a begin timer=1487748505823
a end timer=1487748510826
b begin timer=1487748510827
b end timer=1487748515828
c begin timer=1487748515828
c end timer=1487748520833
- 构造函数permits参数作用
参数permits代表同一时间内,最多允许有x个线程可以执行acquire()和release()之间的代码。我们将上例的Service改造一下,Run类不变
package com.wjg.unit1; import java.util.concurrent.Semaphore; public class Service {
//我们将premits参数值改为2
private Semaphore semaphore = new Semaphore(2);
public void testMethod(){
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+" begin timer="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+" end timer="+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
} }
} 运行结果:
a begin timer=1487749198356
b begin timer=1487749198357
b end timer=1487749203359
a end timer=1487749203359
c begin timer=1487749203359
c end timer=1487749208360
- 方法acquire(int permits)使用
方法acquire(int permits)功能就是每调用1次就使用x个许可。
这个有一点说明一下,acquire方法做的是减法操作,release方法做的是加法操作,构造函数new Semaphore(5)中的5并不是最终的许可数量,仅仅是初始化的状态值,是可以动态改变的。
- 方法acquireUninterruptibly()使用
此方法作用是使等待进入acquire()方法的线程,不允许被中断。我们先看一下被中断的例子
package com.wjg.unit1; import java.util.concurrent.Semaphore; public class Service {
private Semaphore semaphore = new Semaphore(1); public void testMethod(){
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+" begin timer="+System.currentTimeMillis());
for (int i = 0; i < Integer.MAX_VALUE; i++) {
String newString = new String();
Math.random();
}
System.out.println(Thread.currentThread().getName()+" end timer="+System.currentTimeMillis());
} catch (InterruptedException e) {
System.out.println("线程"+Thread.currentThread().getName()+"进入了catch");
e.printStackTrace();
}finally {
semaphore.release();
}
}
} package com.wjg.unit1; public class Run {
public static void main(String[] args) throws InterruptedException {
Service service = new Service();
Run run = new Run();
ThreadA a = run.new ThreadA(service);
a.setName("a");
a.start(); ThreadB b = run.new ThreadB(service);
b.setName("b");
b.start(); Thread.sleep(1000);
//中断b线程
b.interrupt();
System.out.println("main 中断了b");
} public class ThreadA extends Thread{
private Service service; public ThreadA(Service service) {
super();
this.service = service;
} @Override
public void run() {
service.testMethod();
} } public class ThreadB extends Thread{
private Service service; public ThreadB(Service service) {
super();
this.service = service;
} @Override
public void run() {
service.testMethod();
} }
} 执行结果:
a begin timer=1487751504264
main 中断了b
java.lang.InterruptedException
线程b进入了catch
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:996)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1303)
at java.util.concurrent.Semaphore.acquire(Semaphore.java:317)
at com.wjg.unit1_1_4.Service.testMethod(Service.java:10)
at com.wjg.unit1_1_4.Run$ThreadB.run(Run.java:46)
a end timer=1487751505711
以上的例子就是把等待获取许可的线程B手动结束了,下面的例子是利用acquireUninterruptibly()方法阻止等待获取许可的线程中断。
package com.wjg.unit1_1_4; import java.util.concurrent.Semaphore; public class Service {
private Semaphore semaphore = new Semaphore(1); public void testMethod(){
try {
//此处阻止等待获取许可的线程被中断
semaphore.acquireUninterruptibly();
System.out.println(Thread.currentThread().getName()+" begin timer="+System.currentTimeMillis());
for (int i = 0; i < Integer.MAX_VALUE/50; i++) {
String newString = new String();
Math.random();
}
System.out.println(Thread.currentThread().getName()+" end timer="+System.currentTimeMillis());
} finally {
semaphore.release();
}
}
} 执行结果
a begin timer=1487751777062
main 中断了b
a end timer=1487751778455
b begin timer=1487751778455
b end timer=148775177963
- 方法availablePermits()和drainPermits()使用
availablePermits() 返回Semaphore对象中当前可用的许可数
drainPermits() 获取并返回立即可用的许可个数,并且将可用许可置0
- 方法getQueueLength()和hasQueuedThreads()使用
getQueueLength() 返回等待可续的线程个数
hasQueuedThreads() 判断是否还有等待许可的线程
这两个方法通常都是在判断当前有没有等待许可的线程信息时使用。
- 公平与非公平信号量
公平信号量是指获得锁的顺序与线程启动的顺序有关,非公平信息量就是无关的了。
非公平信号量线程启动的顺序与调用semaphore.acquire()的顺序无关,也就是线程先启动了并不代表先获得许可。
公平与不公平通过Semaphore类的构造函数new Semaphore(int permits,boolean fair)的第二个参数fair决定。
- 方法tryAcquire()作用
无参的tryAcquire()作用就是尝试地获得一个许可,如果获取不到则返回false,此方法通常与if语句结合使用,具有不阻塞的特点。
- 方法tryAcquire(int permits)使用
作用是尝试获取x个许可,如果湖区不到则返回false。
- 方法tryAcquire(long timeout,TimeUnit unit)使用
作用是在指定的时间内尝试地获取1个许可,如果获取不到则返回false,此处会有阻塞。
- 方法tryAcquire(int permits,long timeout,TimeUnit unit)使用
作用是在指定的时间内尝试地获取x个许可,如果获取不到则返回false,此处会有阻塞。
注:本系列笔记均参考自《Java并发编程 核心方法与框架》此书。
多线程编程(一)-Semaphore(信号量)的使用的更多相关文章
- python网络编程--线程Semaphore(信号量)
一:Semaphore(信号量) 互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才 ...
- 多线程编程-- part 9 信号量:Semaphore
Semaphore简介 Semaphore是一个计数信号量,它的本质是一个"共享锁". 信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可:当信号量 ...
- Java核心-多线程-并发控制器-Semaphore信号量
Semaphore是非常有用的一个多线程并发控制组件(Java还有CountDownLatch.CyclicBarrier.Exchanger多线程组件),它相当于是一个并发控制器,是用于管理信号量的 ...
- C++多线程同步之Semaphore(信号量)
一.线程间同步的几种方式 从上篇博文中可以发现,当多个线程对同一资源进行使用时,会产生“争夺”的情况,为了避免这种情况的产生,也就出现了线程间的同步这个技术.线程间的同步有多种方式,在接下来的博文中我 ...
- java 多线程 28 : 多线程组件之 Semaphore 信号量
Semaphore是非常有用的一个组件,它相当于是一个并发控制器,是用于管理信号量的.构造的时候传入可供管理的信号量的数值,这个数值就是控制并发数量的,就是同时能几个线程访问.我们需要控制并发的代码, ...
- Linux多线程编程-信号量
在Linux中.信号量API有两组.一组是多进程编程中的System V IPC信号量.另外一组是我们要讨论的POSIX信号量. 这两组接口类似,但不保证互换.POSIX信号量函数都已sem_开头,并 ...
- Linux下多线程编程-信号量
今天来谈谈线程的同步--信号量. 首先来看看一些概念性的东西: 如进程.线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行:B依言执行,再将结果给 ...
- 【C/C++多线程编程之七】pthread信号量
多线程编程之信号量 Pthread是 POSIX threads 的简称.是POSIX的线程标准. 相互排斥量用来处理一个共享资源的同步訪问问题,当有多个共享资源时,就须要 ...
- 多线程锁:Mutex互斥体,Semaphore信号量,Monitor监视器,lock,原子操作InterLocked
Mutex类 “mutex”是术语“互相排斥(mutually exclusive)”的简写形式,也就是互斥量.互斥量跟临界区中提到的Monitor很相似,只有拥有互斥对象的线程才具有访问资源的权限, ...
随机推荐
- web项目开发最佳做法
一个成熟的web项目应该具备以下基础代码或做法 1.前端基础框架: 统一的ajax 通信/表单提交及调用结果弹窗显示 统一的数据验证 统一的数据列表 2.后端基础框架: 统一的异常处理捕获,可针对具体 ...
- Nuget~打包时添加powershell初始化脚本
对于进行nuget打包时,有时我们需要添加一个配置文件,就是一些文本文件,而这些文件我们在网站发布时需要同时复制到输出目录,否则会出现文件丢失的问题,我们在打包时通过添加powershell脚本来解决 ...
- 经典的兔子生兔子问题(C#递归解法)
古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 思路:先求出每个月新增的兔子,再用循环求和即可算出这个月 ...
- 浅谈TCP通讯
基于Tcp协议的Socket通讯类似于B/S架构,面向连接,但不同的是服务器端可以向客户端主动推送消息. 使用Tcp协议通讯需要具备以下几个条件: (1).建立一个套接字(Socket) (2).绑定 ...
- sqlserver常用函数
1.字符串函数 --ascii函数,返回字符串最左侧字符的ascii码值 SELECT ASCII('dsd') AS asciistr --ascii代码转换函数,返回指定ascii值对应的字符 ) ...
- how to trace the error log
Executed as user: WTC\Ebw.Admin. Transaction (Process ID 95) was deadlocked on lock resources with a ...
- SpringMvc-ModelAndView 结果出不来 显示路径问题 解决办法
今天写SpringMVC的时候 写ModelAndView的时候 死活跳不过页面去-一直报错 显示路径也错误 查看导包问题 应该: import org.springframework.web.se ...
- OC中NSClassFromString()与NSStringFromClass()的用法及应用场景
1.NSClassFromString()利用一个字符串创建一个类,我是在标签控制器中 UITabBarController中创建它的子控制器中使用的 - (void)viewDidLoad { [s ...
- Python数据分析之文本处理词频统计
1.项目背景: 原本计划着爬某房产网站的数据做点分析, 结果数据太烂了,链家网的数据干净点, 但都是新开楼盘,没有时间维度,分析意义不大. 学习的步伐不能ting,自然语言处理还的go on 2.分析 ...
- ROS初次实践(小海龟)
启动ROS Master 启动小海龟仿真器 启动海龟控制节点(方向键控制海龟运动) rqt_graph可视化工具 /rosout节点必须存在,订阅所有节点的日志信息. 当前系统当中存在的节点. 了解当 ...