交替打印字符串

交替打印字符串

编写一个可以从 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

假设有这么一个类:

1
2
3
4
5
6
7
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 实例会被如下四个线程使用:

  1. 线程A将调用 fizz() 来判断是否能被 3 整除,如果可以,则输出 fizz
  2. 线程B将调用 buzz() 来判断是否能被 5 整除,如果可以,则输出 buzz
  3. 线程C将调用 fizzbuzz() 来判断是否同时能被 3 和 5 整除,如果可以,则输出 fizzbuzz
  4. 线程D将调用 number() 来实现输出既不能被 3 整除也不能被 5 整除的数字。
  • 什么时候使用if (...) xx.wait() / cond.await() 什么时候使用while(...) xx.wait() / cond.await() ?

    最好的方式就是根据代码自己模拟一下,if 不执行的话就要执行else, while则是一个循环。

  • 如何避免未拿到锁最后还需释放锁导致抛出异常?

    lock.lock()放在try前面,只有当确定拿到锁之后,在执行try..finally

信号量

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
class FizzBuzz {

private Semaphore nu = new Semaphore(1);
private Semaphore f = new Semaphore(0);
private Semaphore b = new Semaphore(0);
private Semaphore fb = new Semaphore(0);

private int n;

public FizzBuzz(int n) {
this.n = n;
}

// printFizz.run() outputs "fizz".
public void fizz(Runnable printFizz) throws InterruptedException {
for(int i = 1; i <= n; i++) {
if(i % 3 == 0 && i % 5 != 0){
f.acquire();
printFizz.run();
nu.release();
}
}

}

// printBuzz.run() outputs "buzz".
public void buzz(Runnable printBuzz) throws InterruptedException {
for(int i = 1; i <= n; i++) {
if(i % 5 == 0 && i % 3 != 0){
b.acquire();
printBuzz.run();
nu.release();
}
}
}

// printFizzBuzz.run() outputs "fizzbuzz".
public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
for(int i = 15; i <= n; i += 15) {
fb.acquire();
printFizzBuzz.run();
nu.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++) {
nu.acquire();
if(i % 3 == 0 && i % 5 == 0) {
fb.release();
}
else if(i % 3 == 0) {
f.release();
}
else if(i % 5 == 0) {
b.release();
} else {
printNumber.accept(i);
nu.release();
}
}
}
}

ReentrantLock+Condition(1)

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
class FizzBuzz {
private int n;
private volatile int i = 1;
private Lock lo = new ReentrantLock();
private Condition cond = lo.newCondition();

public FizzBuzz(int n) {
this.n = n;
}

// printFizz.run() outputs "fizz".
public void fizz(Runnable printFizz) throws InterruptedException {
lo.lock();
try {
while (i <= n) {
if (i % 3 == 0 && i % 5 != 0) {
printFizz.run();
i++;
cond.signalAll();
} else {
cond.await();
}
}
} finally {
lo.unlock();
}
}

// printBuzz.run() outputs "buzz".
public void buzz(Runnable printBuzz) throws InterruptedException {
lo.lock();
try {
while (i <= n) {
if (i % 3 != 0 && i % 5 == 0) {
printBuzz.run();
i++;
cond.signalAll();
} else {
cond.await();
}
}
} finally {
lo.unlock();
}
}

// printFizzBuzz.run() outputs "fizzbuzz".
public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
lo.lock();
try {
while (i <= n) {
if (i % 3 == 0 && i % 5 == 0) {
printFizzBuzz.run();
i++;
cond.signalAll();
} else {
cond.await();
}
}
} finally {
lo.unlock();
}
}

// printNumber.accept(x) outputs "x", where x is an integer.
public void number(IntConsumer printNumber) throws InterruptedException {
lo.lock();
try {
while (i <= n) {
if (i % 3 != 0 && i % 5 != 0) {
printNumber.accept(i);
i++;
cond.signalAll();
} else {
cond.await();
}
}
} finally {
lo.unlock();
}
}

public static void main(String[] args) throws InterruptedException {
FizzBuzz fizzBuzz = new FizzBuzz(20);
CountDownLatch latch = new CountDownLatch(4);
Runnable fizz = () -> {
try {
fizzBuzz.fizz(() -> System.out.println("fizz"));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
Runnable buzz = () -> {
try {
fizzBuzz.buzz(() -> System.out.println("buzz"));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
Runnable fizzbuzz = () -> {
try {
fizzBuzz.fizzbuzz(() -> System.out.println("fizzbuzz"));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
Runnable number = () -> {
try {
fizzBuzz.number(value -> System.out.println(value));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
new Thread(fizz).start();
new Thread(buzz).start();
new Thread(fizzbuzz).start();
new Thread(number).start();
latch.await();
System.out.println("done...");
}
}

ReentrantLock+Condition(2)

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
class FizzBuzz {
private int n;
private volatile int value = 1;

private static ReentrantLock lock = new ReentrantLock();

private static Condition condition = lock.newCondition();

public FizzBuzz(int n) {
this.n = n;
}

// printFizz.run() outputs "fizz".
public void fizz(Runnable printFizz) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if (i % 3 != 0 || i % 5 == 0) {
continue;
}
lock.lock();
try {
while (i != value) {
condition.await();
}
printFizz.run();
value++;
condition.signalAll();
} finally {
lock.unlock();
}
}
}

// printBuzz.run() outputs "buzz".
public void buzz(Runnable printBuzz) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if (i % 5 != 0 || i % 3 == 0) {
continue;
}

try {
lock.lock();
while (i != value) {
condition.await();
}
printBuzz.run();
value++;
condition.signalAll();
} finally {
lock.unlock();
}
}
}

// printFizzBuzz.run() outputs "fizzbuzz".
public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if (i % 5 != 0 || i % 3 != 0) {
continue;
}
lock.lock();
try {
while (i != value) {
condition.await();
}
printFizzBuzz.run();
value++;
condition.signalAll();
} finally {
lock.unlock();
}
}
}

// printNumber.accept(x) outputs "x", where x is an integer.
public void number(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if (i % 5 == 0 || i % 3 == 0) {
continue;
}
lock.lock();
try {
while (i != value) {
condition.await();
}
printNumber.accept(value);
value++;
condition.signalAll();
} finally {
lock.unlock();
}
}
}


public static void main(String[] args) throws InterruptedException {
FizzBuzz fizzBuzz = new FizzBuzz(20);
CountDownLatch latch = new CountDownLatch(4);
Runnable fizz = () -> {
try {
fizzBuzz.fizz(() -> System.out.println("fizz"));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
Runnable buzz = () -> {
try {
fizzBuzz.buzz(() -> System.out.println("buzz"));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
Runnable fizzbuzz = () -> {
try {
fizzBuzz.fizzbuzz(() -> System.out.println("fizzbuzz"));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
Runnable number = () -> {
try {
fizzBuzz.number(value -> System.out.println(value));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
new Thread(number).start();
new Thread(fizz).start();
new Thread(buzz).start();
new Thread(fizzbuzz).start();
latch.await();
System.out.println("done...");
}
}

Synchronized

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
class FizzBuzz {
private int n;
private volatile int value = 1;

public FizzBuzz(int n) {
this.n = n;
}

// printFizz.run() outputs "fizz".
public void fizz(Runnable printFizz) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if (i % 3 != 0 || i % 5 == 0) {
continue;
}
synchronized (this) {
while (i != value) {
this.wait();
}
printFizz.run();
value++;
this.notifyAll();
}
}
}

// printBuzz.run() outputs "buzz".
public void buzz(Runnable printBuzz) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if (i % 5 != 0 || i % 3 == 0) {
continue;
}
synchronized (this) {
while (i != value) {
this.wait();
}
printBuzz.run();
value++;
this.notifyAll();
}
}
}

// printFizzBuzz.run() outputs "fizzbuzz".
public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if (i % 5 != 0 || i % 3 != 0) {
continue;
}
synchronized (this) {
while (i != value) {
this.wait();
}
printFizzBuzz.run();
value++;
this.notifyAll();
}
}
}

// printNumber.accept(x) outputs "x", where x is an integer.
public void number(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if (i % 5 == 0 || i % 3 == 0) {
continue;
}
synchronized (this) {
while (i != value) {
this.wait();
}
printNumber.accept(value);
value++;
this.notifyAll();
}
}
}


public static void main(String[] args) throws InterruptedException {
FizzBuzz fizzBuzz = new FizzBuzz(20);
CountDownLatch latch = new CountDownLatch(4);
Runnable fizz = () -> {
try {
fizzBuzz.fizz(() -> System.out.println("fizz"));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
Runnable buzz = () -> {
try {
fizzBuzz.buzz(() -> System.out.println("buzz"));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
Runnable fizzbuzz = () -> {
try {
fizzBuzz.fizzbuzz(() -> System.out.println("fizzbuzz"));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
Runnable number = () -> {
try {
fizzBuzz.number(value -> System.out.println(value));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
};
new Thread(fizz).start();
new Thread(buzz).start();
new Thread(fizzbuzz).start();
new Thread(number).start();
latch.await();
System.out.println("done...");
}
}

交替打印字符串
http://example.com/2023/10/25/交替打印字符串/
作者
ykexc
发布于
2023年10月25日
许可协议