subject
Original question connection leetcode1195
Title Description:
Write a program that can output a string representing this number from 1 to n, but:
- If this number can be divided by 3, output "fizz".
- If this number can be divided by 5, output "buzz".
- If this number can be divided by 3 and 5 at the same time, output "fizzbuzz".
For example, when n = 15, output: 1, 2, fizz, 4, buzz, fizz, 7, 8, fizz, buzz, 11, fizz, 13, 14, fizzbuzz.
Suppose there is such a class:
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 }
Please implement a multi-threaded version of FizzBuzz with four threads. The same FizzBuzz instance will be used by the following four threads:
- Thread A will call fizz() to determine whether it can be divided by 3. If it can, it will output fizz.
- Thread B will call buzz() to determine whether it can be divided by 5. If so, it will output buzz.
- Thread C will call fizzbuzz() to determine whether it can be divided by 3 and 5 at the same time. If so, output fizzbuzz.
- Thread D will call number() to output a number that cannot be divided by either 3 or 5.
Tips:
Relevant methods for printing strings have been provided in this question, such as printFizz(). Please refer to the notes in the answer template for the specific method name.
The code implementation is given first
class FizzBuzz { private int n; private static CyclicBarrier barrier = new CyclicBarrier(4); 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){ printFizz.run(); } try{ barrier.await(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } // printBuzz.run() outputs "buzz". public void buzz(Runnable printBuzz) throws InterruptedException { for(int i = 1 ; i <= n; i++ ){ if(i % 3 != 0 && i % 5 == 0){ printBuzz.run(); } try{ barrier.await(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } // printFizzBuzz.run() outputs "fizzbuzz". public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException { for(int i = 1 ; i <= n; i++ ){ if(i % 3 == 0 && i % 5 == 0){ printFizzBuzz.run(); } try{ barrier.await(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } // 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 % 3 != 0 && i % 5 != 0){ printNumber.accept(i); } try{ barrier.await(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } }
Use the CyclicBarrier class, which is implemented based on the principle of ReentrantLock+condition, and recommend learning articles CyclicBarrier learning articles
Explanation of ideas:
- Each method loops from 1 to n and prints only when it meets the conditions.
- When i=1, printFizz executes the code of i=1. If the judgment conditions are not met, reduce the cyclicBarrier by one and wait.
- printBuzz and printFizzBuzz execute i=1 code, and the same is true.
- Until printNumber is executed, cyclicBarrier is also reduced by one, and the other three threads are waiting for the last thread to be reduced by one. It can be understood this way. When i is a certain value, the judgment conditions of the four methods are complementary, that is, only one method can be executed at the same time.
- To sum up, when i=n, we use the cyclicBarrier control to let four threads judge whether they meet their own judgment conditions. After all four threads judge, we can judge i=n+1