本篇将介绍使用Semaphore来实现生产者模型
Android-使用Semaphore实现生产者消费者模型
介绍
问题
生产者消费者模型也就是为了解决:生产者和消费者在同一时间段内共用同一个存储空间,当双方生成/消费速度不对等时,数据不同步的问题
解决
那么还是生产者和消费者在同一时间段内共用同一个存储空间,当生产/消费速度不对等时。那么就让当存储空间为空时,消费者阻塞,当存储空间满时,生产者阻塞。
Semaphore
介绍
Semaphore也叫信号量,可以控制同时访问特定资源的线程数,通过协调各个线程来保证合理的使用
Semaphore内部维护了一组虚拟的许可,许可的数量可以通过构造方法来进行设定
- 在访问特定资源前,先需要调用
acquire()
进行获取许可,如果当前可用许可为0,则会进入阻塞状态,直到有可用许可 - 访问完特定资源后,需要调用
release()
进行释放许可
代码
下面将以添加商品和消费商品为例
首先创建生产者与消费者
1
2val mProduce = Semaphore(5)
val mConsumer = Semaphore(5)这里给定了信号量最大就是5,也就是说最多缓存5个数据
在创建一个添加商品的许可和商品缓存区
1
2val mutex = Semaphore(1)
val buffer = LinkedList<String>()mutex: 表示一次只能添加/消费一个商品
buffer: 用于缓存商品
添加商品方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29suspend fun add(name: String) {
// 尝试申请商品许可,用于添加商品
if (mProduce.tryAcquire()) {
delay(1000) // 模拟耗时
// 申请(添加/消费)商品许可
mutex.acquire()
// 添加到缓存区
buffer.push("${name}雨伞")
println("添加商品 -> ${name}雨伞")
// 添加完毕,释放许可
mutex.release()
// 防止第一次添加商品,顾客还没有申请消费许可
try {
index++
// 释放消费许可,也就说添加与消费成一一对应
// 添加一个商品就可以申请一个消费许可
// 消费一个商品就可以申请一个添加许可
mConsumer.release()
} catch (e: Exception) {
}
}else{
// 无许可,等待
delay(1500)
println("商品已满")
}
}这是伪代码,里面使用协程进行模拟耗时操作
消费商品
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29suspend fun consumer() {
// 尝试申请消费许可
if (mConsumer.tryAcquire()) {
delay(5000)
// 申请(添加/消费)商品许可
mutex.acquire()
try {
// 获取缓存区中最前面的商品
val s = buffer.removeFirst()
if (s != null) {
println("购买商品->${s}")
} else {
mutex.release()
}
} catch (e: NoSuchElementException) { }
mutex.release()
// 释放商品许可
try {
mProduce.release()
} catch (e: Exception) { }
} else {
delay(1500)
println("没有商品,等待中")
}
// 伪代码,无限递过,不停的获取
consumer()
}在上述代码中,商品添加一个只需1秒,消费一个商品需要5秒。也就是速度不对等,让我们运行代码看看结果如何把
1
2
3
4
5
6
7
8
9
10fun main(): Unit = runBlocking {
var index = 0
launch {
while (true) {
add("$index")
index+
}
}
consumer()
}运行效果:
可以看到在,在商品许可无法申请的情况下,商品会进行阻塞,直到有许可为止