1115. 交替打印 FooBar【中等】
1. 📝 题目描述
给你一个类:
txt
class FooBar {
public void foo() {
for (int i = 0; i < n; i++) {
print("foo");
}
}
public void bar() {
for (int i = 0; i < n; i++) {
print("bar");
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
两个不同的线程将会共用一个 FooBar 实例:
- 线程 A 将会调用
foo()方法,而 - 线程 B 将会调用
bar()方法
请设计修改程序,以确保 "foobar" 被输出 n 次。
示例 1:
txt
输入:n = 1
输出:"foobar"
解释:这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。1
2
3
2
3
示例 2:
txt
输入:n = 2
输出:"foobarfoobar"
解释:"foobar" 将被输出两次。1
2
3
2
3
提示:
1 <= n <= 1000
2. 🎯 s.1 - 信号量
js
// JavaScript 无原生线程支持,使用 Promise 模拟
class FooBar {
constructor(n) {
this.n = n
this.fooTurn = true
this.resolve = null
this.promise = new Promise((r) => (this.resolve = r))
}
async foo(printFoo) {
for (let i = 0; i < this.n; i++) {
while (!this.fooTurn) await this.promise
printFoo()
this.fooTurn = false
const old = this.resolve
this.promise = new Promise((r) => (this.resolve = r))
old()
}
}
async bar(printBar) {
for (let i = 0; i < this.n; i++) {
while (this.fooTurn) await this.promise
printBar()
this.fooTurn = true
const old = this.resolve
this.promise = new Promise((r) => (this.resolve = r))
old()
}
}
}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
29
30
31
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
29
30
31
- 时间复杂度:
,循环 n 次 - 空间复杂度:
,只使用常数级别的同步原语
算法思路:
- 使用两个信号量控制 foo 和 bar 的交替执行
- foo 执行后释放 bar 的信号量,bar 执行后释放 foo 的信号量
- 初始时 foo 的信号量为 1,bar 的为 0,保证 foo 先执行