当前位置:网站首页>线程间控制之Semaphore使用介绍
线程间控制之Semaphore使用介绍
2022-04-23 14:07:00 【pureluckyfish】
Semaphore(信号量)通常用于限制访问某些(物理或逻辑)资源线程的数量。
一个信号量维护一组许可证。每个acquire()都会阻塞,直到获得许可证;每个release()会释放许可证。如果没有线程需要获取许可证;信号量只是像其它池对象那样保持一个可用许可证的计数。
池对象:线程池、数据库连接池等,创建一个池子,池子中已经建立好了连接,需要使用的时候直接从池子中拿来用。
一、Pool类源代码
例子,这里有一个Pool类,它使用信号量来控制对项目池的访问
package ThreadStudy;
import java.util.concurrent.Semaphore;
//信号量通常用于限制访问某些(物理或逻辑)资源线程的数量
public class Pool {
private final static int MAX_AVAILABLE = 100;
//创建一个具有100许可证的信号量,采用公平方式获取许可证
private final Semaphore semaphore = new Semaphore(MAX_AVAILABLE, true);
public Object getItem() throws Exception {
semaphore.acquire();
return getNextAvailableItem();
}
public void putItem(Object x) {
if (markAsUnused(x)) {
semaphore.release();
}
}
// 管理的任何类型的项目
Object[] items = new Object[MAX_AVAILABLE];
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;
}
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;
}
}
二、二进制信号量用法
一个初始化为1的信号量,并且它最多只能有一个permit可用,可以作为互斥锁。这通常被称为二进制信号量,因为它只有两种状态:一个可用的许可证,或零可用的许可证。当以这种方式使用时,二进制信号量具有这样的属性(与许多锁实现不同),即“锁”可以由所有者以外的线程释放(因为信号量没有所有权的概念)。这在某些特定的上下文中可能很有用,比如死锁恢复。
package ThreadStudy;
import java.util.concurrent.Semaphore;
public class SemaphoreT2 {
public static void main(String[] args) throws Exception {
Semaphore semophore = new Semaphore(1);
semophore.acquire();
new Thread(new Runnable() {
@Override
public void run() {
try {
// 获取不到许可证,线程阻塞
System.out.println(Thread.currentThread().getName()+"获取不到许可证,线程阻塞");
semophore.acquire();
System.out.println(Thread.currentThread().getName()+"获取到许可证,线程继续执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
// 释放许可证
System.out.println(Thread.currentThread().getName()+"释放许可证");
Thread.sleep(3000);
semophore.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
三、Semaphore类中各种方法使用介绍
1、俩个构造方法的区别,公平非公平!
Semaphore(int permits) | 创建一个具有给定许可数和不公平设置的信号量 |
Semaphore(int permits, boolean fair) | 创建一个具有给定许可数和给定公平性设置的信号量 |
2、普通方法
获取许可证 | 释放许可证 |
acquire() 从这个信号量获得一个许可,阻塞直到一个可用,或者线程被中断 |
release() 释放一个许可证,将其返回给信号量 |
acquire(int permits) 从信号量获取给定数量的许可 |
release(int permits) 释放给定的许可证数量,将它们返回给信号量 |
从信号量获得一个许可,阻塞直到一个可用 |
|
acquireUninterruptibly(int permits) 从信号量获取给定数量的许可 |
|
获取到许可证返回true,获取不到返回false |
|
tryAcquire(int permits) | |
tryAcquire(int permits, long timeout, TimeUnit unit) | |
tryAcquire(long timeout, TimeUnit unit) |
3、代码示例
package ThreadStudy;
import java.util.concurrent.Semaphore;
public class SemaphoreT1 {
public static void main(String[] args) {
int MAX = 10;
// 创建10个许可证
Semaphore s = new Semaphore(MAX);
for (int i = 0; i < MAX; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("等待获取许可证的线程数量评估值:" + s.getQueueLength());
// 获取二个许可证
s.acquire(2);
System.out.println("返回此信号量中可用的当前许可数,此方法通常用于调试和测试目的:" + s.availablePermits());
System.out.println("获取并返回所有立即可用的许可:" + s.drainPermits());
// 和acquire的唯一区别就是,一直处于阻塞状态,除了获取到一个许可证
s.acquireUninterruptibly();
// 获取许可证,并且返回true,便于代码流程控制
if (s.tryAcquire()) {
System.out.println("tryAcquire返回为true");
} else {
System.out.println("tryAcquire返回为false");
}
Thread.sleep(1000);
// 获取一个许可证
s.acquire();
// 获取5个许可证
s.acquire(5);
System.out.println("线程获取到许可:" + Thread.currentThread().getName());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
}
版权声明
本文为[pureluckyfish]所创,转载请带上原文链接,感谢
https://blog.csdn.net/sinat_33918956/article/details/122533983
边栏推荐
- 第四届“传智杯”全国大学生IT技能大赛(决赛B组) 题解
- JDBC详解
- Check in system based on ibeacons
- 封装logging模块
- 在MAC上安装mysql
- 政务云迁移实践 北明数科使用HyperMotion云迁移产品为某政府单位实施上云迁移项目,15天内完成近百套主机迁移
- Wechat applet communicates with esp8266 based on UDP protocol
- HyperMotion云迁移助力中国联通,青云完成某央企上云项目,加速该集团核心业务系统上云进程
- Jmeter安装教程以及我遇到的问题的解决办法
- RecyclerView高级使用(二)-垂直拖拽排序的简单实现
猜你喜欢
Some experience of using dialogfragment and anti stepping pit experience (getactivity and getdialog are empty, cancelable is invalid, etc.)
云迁移的六大场景
org.apache.parquet.schema.InvalidSchemaException: A group type can not be empty. Parquet does not su
基于CM管理的CDH6.3.2集群集成Atlas2.1.0
容灾有疑问?点这里
更改plsql工具栏的图标大小
Wechat applet initializes Bluetooth, searches nearby Bluetooth devices and connects designated Bluetooth (I)
Gartner预测云迁移规模大幅增长;云迁移的优势是什么?
01-NIO基础之ByteBuffer和FileChannel
查询2013年到2021年的数据,只查询到2020的数据,遇到了这个问题所进行的解决办法
随机推荐
困扰多年的系统调研问题有自动化采集工具了,还是开源免费的
postman批量生产body信息(实现批量修改数据)
Request module
Easyexcel读取excel表地理位置数据,按中文拼音排序
关于Jmeter启动闪退问题
星界边境文本自动翻译机(高级版)使用说明
leetcode--357. Count the number of different figures
Chrome插件 之 Selenium IDE、XPath 安装
RobotFramework 之 用例标签机制
利用json-server在本地创建服务器请求
MYSQL 主从同步避坑版教程
RobotFramework 之 项目框架
MySQL数据库讲解(七)
OpenStack如何跨版本升级
Call wechat customer service applet
云迁移的六大场景
Recyclerview advanced use (II) - simple implementation of vertical drag and drop sorting
Promtail + Loki + Grafana 日志监控系统搭建
VMware installation 64 bit XP Chinese tutorial
jsp学习1