并发工具类——Semaphore
本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。
Semaphore([' seməf :(r)])的主要作用是控制线程并发的数量。我们可以将Semaphore想象成景区的一个门卫,这个门卫负责发放景区入园的许可证。
景区为了游客的入园观赏体验,决定最多允许200个有个同时在园内观赏。那么这个门卫在每天开园的时候手中都会有200张许可证,每当一个游客要入园的时候门卫会给游客发放一张许可证,当门卫手中的许可证发完之后再有游客需要入园的话就必须等待。
当游客观赏完毕之后,出园的时候需要将许可证交还到门卫手上。门卫将这些交还的许可证再发等待的游客,这些游客就能顺利入园了。
Semaphore的API简介
Semaphore的API使用起来也比较简单,常见的API简介如下:
- Semaphore(int permits):构造方法,创建具有给定许可数的计数信号量并设置为非公平信号量。
- Semaphore(int permits,boolean fair):构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量。
- void acquire():从此信号量获取一个许可前线程将一直阻塞。相当于一辆车占了一个车位。
- void acquire(int n):从此信号量获取给定数目许可,在提供这些许可前一直将线程阻塞。比如n=2,就相当于一辆车占了两个车位。
- boolean tryAcquire(int permits, long timeout, TimeUnit unit):尝试获取,在给定的时间内没获取到资源超时
- void release():释放一个许可,将其返回给信号量。就如同车开走返回一个车位。
- void release(int n):释放n个许可。
- int availablePermits():当前可用的许可数。
Semaphore的常见用法
下面给出一个Oracle官方文档中的列子代码:
class Pool {
// 可同时访问资源的最大线程数
private static final int MAX_AVAILABLE = 100;
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
// 共享资源
protected Object[] items = new Object[MAX_AVAILABLE];
protected boolean[] used = new boolean[MAX_AVAILABLE];
public Object getItem() throws InterruptedException {
available.acquire();
return getNextAvailableItem();
}
public void putItem(Object x) {
if (markAsUnused(x))
available.release();
}
private synchronized Object getNextAvailableItem() {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (!used[i]) {
used[i] = true;
return items[i];
}
}
return null;
}
private 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;
}
}
items数组可以看成是我们的共享资源,当有线程尝试使用共享资源时,我们要求线程先获得“许可”(调用Semaphore 的acquire方法),这样线程就拥有了权限,否则就需要等待。当使用完资源后,线程需要调用Semaphore 的release方法释放许可。
Semaphore并不能替代synchronized
有些书中提到:如果将Semaphore的许可证数量设置成1的话,就能实现synchronized的功能。其实这种说法是不对的。
下面使用Semaphore来控制对一个账户进行并发存钱和取钱的动作,如果Semaphore能实现synchronized的功能的话,账户最后的余额应该还是10000,但代码执行后的结果并不是这样。大家可以执行下面的代码看下结果。
public static final int THREAD_COUNT = 100;
public static void main(String[] args) {
BankAccount myAccount = new BankAccount("accountOfMG", 10000.00);
for (int i = 0; i < THREAD_COUNT; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
int var = new Random().nextInt(100);
Thread.sleep(var);
} catch (InterruptedException e) {
e.printStackTrace();
}
double deposit = myAccount.deposit(1000.00);
System.out.println(Thread.currentThread().getName() + " balance1:" + deposit);
}
}).start();
}
for (int i = 0; i < THREAD_COUNT; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
int var = new Random().nextInt(100);
Thread.sleep(var);
} catch (InterruptedException e) {
e.printStackTrace();
}
double deposit = myAccount.withdraw(1000.00);
System.out.println(Thread.currentThread().getName() + " balance2:" + deposit);
}
}).start();
}
}
private static class BankAccount {
Semaphore semaphore = new Semaphore(1);
String accountName;
double balance;
public BankAccount(String accountName, double balance) {
this.accountName = accountName;
this.balance = balance;
}
public double deposit(double amount) {
try {
semaphore.acquire();
balance = balance + amount;
return balance;
} catch (Exception e) {
throw new RuntimeException("中断...");
} finally {
semaphore.release();
}
}
public double withdraw(double amount) {
try {
semaphore.acquire();
balance = balance - amount;
return balance;
} catch (Exception e) {
throw new RuntimeException("中断...");
} finally {
semaphore.release();
}
}
}
这里Semaphore并不能实现synchronized的功能的原因是:Semaphore并不能保证共享变量的可见性。
实现原理
Semaphore底层原理还是基于AQS机制的。这边就不具体分析了,感兴趣的可以参考我前面关于AQS的文章。
简单总结
- Semaphore只能用来做线程同步——控制线程的执行顺序,但是并不能保证线程安全;
- Semaphore主要用来控制线程的并发数量,通常用在限流组件中。
- Semaphore基于AQS机制实现。
并发工具类——Semaphore的更多相关文章
- 30行自己写并发工具类(Semaphore, CyclicBarrier, CountDownLatch)是什么体验?
30行自己写并发工具类(Semaphore, CyclicBarrier, CountDownLatch)是什么体验? 前言 在本篇文章当中首先给大家介绍三个工具Semaphore, CyclicBa ...
- Java并发工具类Semaphore应用实例
package com.thread.test.thread; import java.util.Random; import java.util.concurrent.*; /** * Semaph ...
- Java多线程并发工具类-信号量Semaphore对象讲解
Java多线程并发工具类-Semaphore对象讲解 通过前面的学习,我们已经知道了Java多线程并发场景中使用比较多的两个工具类:做加法的CycliBarrier对象以及做减法的CountDownL ...
- 【重学Java】多线程进阶(线程池、原子性、并发工具类)
线程池 线程状态介绍 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.线程对象在不同的时期有不同的状态.那么Java中的线程存在哪几种状态呢?Java中的线程 状态被定 ...
- 并发工具类:CountDownLatch、CyclicBarrier、Semaphore
在多线程的场景下,有些并发流程需要人为来控制,在JDK的并发包里提供了几个并发工具类:CountDownLatch.CyclicBarrier.Semaphore. 一.CountDownLatch ...
- Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger
在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...
- Java中的并发工具类(CountDownLatch、CyclicBarrier、Semaphore、Exchanger)
在JDK的并发包里提供了很多有意思的并发工具类.CountDownLatch.CyclicBarrier和Semaphore 工具类提供了一种并发流程控制的手段,Exchanger 工具类则提供了在线 ...
- Java并发(十五):并发工具类——信号量Semaphore
先做总结: 1.Semaphore是什么? Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源. 把它比作是控制流量的红绿灯,比如XX马路要 ...
- 25.大白话说java并发工具类-CountDownLatch,CyclicBarrier,Semaphore,Exchanger
1. 倒计时器CountDownLatch 在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种的业务场景下,通常可以使用Thread类的join ...
随机推荐
- Python下将一般对象打印成Json
有的时候,我们在写Python程序的时候,在处理复杂对象的时候,有的时候过程中调试,需要去看看产生的对象如何,有的时候我们可以把它打印成json来看,这个是个不错的办法. 对每一个对象写一个独立的打印 ...
- H - Tempter of the Bone DFS
小明做了一个很久很久的梦,醒来后他竟发现自己和朋友在一个摇摇欲坠的大棋盘上,他们必须得想尽一切办法逃离这里.经过长时间的打探,小明发现,自己所在的棋盘格子上有个机关,上面写着“你只有一次机会,出发后t ...
- OkHttp 优雅封装 OkHttps 之 回调线程魔变
第一篇:OkHttp 优雅封装 HttpUtils 之 气海雪山初探 第二篇:OkHttp 优雅封装 HttpUtils 之 上传下载解密 简介 HttpUtils 从 v2.3.0 之后便重命名了, ...
- PHP函数:memory_get_usage
memory_get_usage() -返回分配给 PHP 的内存量 说明: memory_get_usage ([ bool $real_usage = false ] ) : int 参数: r ...
- OAuth - 四种方式
OAuth 2.0 的标准是 RFC 6749 文件.该文件先解释了 OAuth 是什么. OAuth 引入了一个授权层,用来分离两种不同的角色:客户端和资源所有者.......资源所有者同意以后,资 ...
- sk-learn实现L2岭回归,对线性回归正则化
岭回归算法: from sklearn.datasets import load_boston from sklearn.externals import joblib from sklearn.li ...
- 如何让ThreadPoolExecutor更早地创建非核心线程
最近在项目中遇到一个需要用线程池来处理任务的需求,于是我用ThreadPoolExecutor来实现,但是在实现过程中我发现提交大量任务时它的处理逻辑是这样的(提交任务还有一个submit方法内部也调 ...
- Python带你做个愉快的"动森"玩家! (超简单代码)
最近Switch上的<动物森友会>可谓是炙手可热,它几乎算是任天堂版的<模拟人生>了,它的最新游戏<集合啦!动物森友会>(以下称“动森”)在发售后,取得了不错的媒体 ...
- thymeleaf 模板语法
模板语法 如何在 script 标签体内部使用 th 获取后端数据 添加如下属性 <script type="text/javascript" th:inline=" ...
- Hexo博客插入图片的方法
Hexo博客插入图片的方法 hexo图片blog hexo blog 插入图片的方法总结 hexo 的blog 内容是根据 markdown 文件的内容生成的html文件, 生成的文件全部在 /pub ...