题目描述
给你一个类:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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"); } } }
|
两个不同的线程将会共用一个 FooBar
实例:
- 线程 A 将会调用
foo()
方法,而
- 线程 B 将会调用
bar()
方法
请设计修改程序,以确保 "foobar"
被输出 n
次。
示例 1:
1 2 3
| 输入:n = 1 输出:"foobar" 解释:这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。
|
示例 2:
1 2 3
| 输入:n = 2 输出:"foobarfoobar" 解释:"foobar" 将被输出两次。
|
提示:
思路
foo 和 bar 之间是同步关系,可以使用信号量来解决这个问题。
- 信号量 s1:foo 已经完成,初始值为 0
- 信号量 s2:bar 已经完成,初始值为 0
foo 执行前需要确保 bar 已经完成,同理 bar 执行前也要确保 foo 已经完成。
注意:开始时,假设 bar 已经完成,因此要在构造函数中,执行 s2.release()
,否则会导致 foo 和 bar 相互等待,从而导致死锁。
1 2 3 4
| public FooBar(int n) { this.n = n; s2.release(); }
|
代码
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
| class FooBar { private int n; private final Semaphore s1 = new Semaphore(0); private final Semaphore s2 = new Semaphore(0); public FooBar(int n) { this.n = n; s2.release(); }
public void foo(Runnable printFoo) throws InterruptedException { for (int i = 0; i < n; i++) { s2.acquire(); printFoo.run(); s1.release(); } }
public void bar(Runnable printBar) throws InterruptedException { for (int i = 0; i < n; i++) { s1.acquire(); printBar.run(); s2.release(); } } }
|