Java多线程:交替打印字符串
文章目录
问题
方法
1.CyclicBarrier
首先需要知道,每个数字对应调用四个方法中的某一个打印语句。对于四个方法,我们可以使其依次遍历1~n,但我们需要满足从小到大按序打印,由于线程运行的速度有快有慢,那么我们必须得建立一个基准,我们可以使用CyclicBarrier让四个线程每次从同一起跑线出发。也就是说我们只需要让四个线程调用的四个方法同时判断同一个数字即可,先判断完的等待后判断完的,四个方法都判断完后再判断下一个数字,利用CyclicBarrier可以实现这一点
代码:
class FizzBuzz {
private int n;
public FizzBuzz(int n) {
this.n = n;
}
public CyclicBarrier cyclicBarrier = new CyclicBarrier(4);
// printFizz.run() outputs "fizz".
public void fizz(Runnable printFizz) throws InterruptedException {
int i;
for (i = 1;i <= n;i++) {
if (i % 3 == 0 && i % 5 != 0) {
printFizz.run();
}
try {
cyclicBarrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
// printBuzz.run() outputs "buzz".
public void buzz(Runnable printBuzz) throws InterruptedException {
int i;
for (i = 1;i <= n;i++) {
if (i % 5 == 0 && i % 3 != 0) {
printBuzz.run();
}
try {
cyclicBarrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
// printFizzBuzz.run() outputs "fizzbuzz".
public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
int i;
for (i = 1;i <= n;i++) {
if (i % 5 == 0 && i % 3 == 0) {
printFizzBuzz.run();
}
try {
cyclicBarrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
// printNumber.accept(x) outputs "x", where x is an integer.
public void number(IntConsumer printNumber) throws InterruptedException {
int i;
for (i = 1;i <= n;i++) {
if (i % 5 != 0 && i % 3 != 0) {
printNumber.accept(i);
}
try {
cyclicBarrier.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
2.Semaphore
首先需要知道,每个数字对应调用四个方法中的某一个打印语句。对于四个方法,我们可以使其依次遍历1~n,但我们需要满足从小到大按序打印。由于线程运行的速度有快有慢,那么我们必须得建立一个基准,这里我们可以使用信号量让四个线程以执行number方法的线程为基准,当某个线程运行速度快于基准线程时,若它要进行打印,我们让其等待基准线程向其发送信号,才能进行打印。同时需要注意,我们也得控制基准线程的步伐,基准线程需等待其他线程打印完成之后,才能进行下一次判断,否则若基准线程过快,可能其他线程还没打印,基准线程就打印了多次。
我们使用信号量fizzbuzzRun,buzzRun,fizzRun
分别表示用于控制fizzbuzz,buzz,fizz
方法对应线程速度的信号量,初始值为0,在打印前,必须获得对应的信号量,而信号量由number方法release,因此若这三个线程速度较快,也不会提前输出,而是会等待number方法对应的线程向其发送信号。使用信号量number
用于控制number
方法对应线程的速度,初始值为1,在对当前遍历的数字进行整除判断前,需要获得number
信号量,number
信号量一方面是在其他三个线程打印完成后release的,另一方面是在number
方法打印完成后release的,也就是进行一次打印后都要释放number
信号量,这样才能保证number
方法能顺利进行下一个数字的判断。
代码:
class FizzBuzz {
private int n;
public FizzBuzz(int n) {
this.n = n;
}
public Semaphore fizzbuzzRun = new Semaphore(0)