comments | difficulty | edit_url | tags | |
---|---|---|---|---|
true |
中等 |
|
编写一个可以从 1 到 n 输出代表这个数字的字符串的程序,但是:
- 如果这个数字可以被 3 整除,输出 "fizz"。
- 如果这个数字可以被 5 整除,输出 "buzz"。
- 如果这个数字可以同时被 3 和 5 整除,输出 "fizzbuzz"。
例如,当 n = 15
,输出: 1, 2, fizz, 4, buzz, fizz, 7, 8, fizz, buzz, 11, fizz, 13, 14, fizzbuzz
。
假设有这么一个类:
class FizzBuzz { public FizzBuzz(int n) { ... } // constructor public void fizz(printFizz) { ... } // only output "fizz" public void buzz(printBuzz) { ... } // only output "buzz" public void fizzbuzz(printFizzBuzz) { ... } // only output "fizzbuzz" public void number(printNumber) { ... } // only output the numbers }
请你实现一个有四个线程的多线程版 FizzBuzz
, 同一个 FizzBuzz
实例会被如下四个线程使用:
- 线程A将调用
fizz()
来判断是否能被 3 整除,如果可以,则输出fizz
。 - 线程B将调用
buzz()
来判断是否能被 5 整除,如果可以,则输出buzz
。 - 线程C将调用
fizzbuzz()
来判断是否同时能被 3 和 5 整除,如果可以,则输出fizzbuzz
。 - 线程D将调用
number()
来实现输出既不能被 3 整除也不能被 5 整除的数字。
提示:
- 本题已经提供了打印字符串的相关方法,如
printFizz()
等,具体方法名请参考答题模板中的注释部分。
class FizzBuzz {
private int n;
public FizzBuzz(int n) {
this.n = n;
}
private Semaphore fSema = new Semaphore(0);
private Semaphore bSema = new Semaphore(0);
private Semaphore fbSema = new Semaphore(0);
private Semaphore nSema = new Semaphore(1);
// printFizz.run() outputs "fizz".
public void fizz(Runnable printFizz) throws InterruptedException {
for (int i = 3; i <= n; i = i + 3) {
if (i % 5 != 0) {
fSema.acquire();
printFizz.run();
nSema.release();
}
}
}
// printBuzz.run() outputs "buzz".
public void buzz(Runnable printBuzz) throws InterruptedException {
for (int i = 5; i <= n; i = i + 5) {
if (i % 3 != 0) {
bSema.acquire();
printBuzz.run();
nSema.release();
}
}
}
// printFizzBuzz.run() outputs "fizzbuzz".
public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
for (int i = 15; i <= n; i = i + 15) {
fbSema.acquire();
printFizzBuzz.run();
nSema.release();
}
}
// printNumber.accept(x) outputs "x", where x is an integer.
public void number(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i++) {
nSema.acquire();
if (i % 3 == 0 && i % 5 == 0) {
fbSema.release();
} else if (i % 3 == 0) {
fSema.release();
} else if (i % 5 == 0) {
bSema.release();
} else {
printNumber.accept(i);
nSema.release();
}
}
}
}
class FizzBuzz {
private:
std::mutex mtx;
atomic<int> index;
int n;
// 这里主要运用到了C++11中的RAII锁(lock_guard)的知识。
// 需要强调的一点是,在进入循环后,要时刻不忘加入index <= n的逻辑
public:
FizzBuzz(int n) {
this->n = n;
index = 1;
}
void fizz(function<void()> printFizz) {
while (index <= n) {
std::lock_guard<std::mutex> lk(mtx);
if (0 == index % 3 && 0 != index % 5 && index <= n) {
printFizz();
index++;
}
}
}
void buzz(function<void()> printBuzz) {
while (index <= n) {
std::lock_guard<std::mutex> lk(mtx);
if (0 == index % 5 && 0 != index % 3 && index <= n) {
printBuzz();
index++;
}
}
}
void fizzbuzz(function<void()> printFizzBuzz) {
while (index <= n) {
std::lock_guard<std::mutex> lk(mtx);
if (0 == index % 15 && index <= n) {
printFizzBuzz();
index++;
}
}
}
void number(function<void(int)> printNumber) {
while (index <= n) {
std::lock_guard<std::mutex> lk(mtx);
if (0 != index % 3 && 0 != index % 5 && index <= n) {
printNumber(index);
index++;
}
}
}
};