在面试中被问到这个问题,试图解决…但是没有成功。我想到了使用CyclicBarrier
有三个线程T1打印1,4,7 … T2打印2,5,8 …,T3打印3,6,9…。您如何同步这三个来打印序列1,2,3,4,5,6,7,8,9…。
我尝试编写并运行以下代码
public class CyclicBarrierTest { public static void main(String[] args) { CyclicBarrier cBarrier = new CyclicBarrier(3); new Thread(new ThreadOne(cBarrier,1,10,"One")).start(); new Thread(new ThreadOne(cBarrier,2,10,"Two")).start(); new Thread(new ThreadOne(cBarrier,3,10,"Three")).start(); } } class ThreadOne implements Runnable { private CyclicBarrier cb; private String name; private int startCounter; private int numOfPrints; public ThreadOne(CyclicBarrier cb, int startCounter,int numOfPrints,String name) { this.cb = cb; this.startCounter=startCounter; this.numOfPrints=numOfPrints; this.name=name; } @Override public void run() { for(int counter=0;counter<numOfPrints;counter++) { try { // System.out.println(">>"+name+"<< "+cb.await()); cb.await(); System.out.println("["+name+"] "+startCounter); cb.await(); //System.out.println("<<"+name+">> "+cb.await()); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } startCounter+=3; } } }
输出
[Three] 3 [One] 1 [Two] 2 [One] 4 [Two] 5 [Three] 6 [Two] 8 [One] 7 [Three] 9 [One] 10 [Two] 11 [Three] 12 [Two] 14 [One] 13 [Three] 15 [One] 16 [Two] 17 [Three] 18 [Two] 20 [One] 19 [Three] 21 [One] 22 [Two] 23 [Three] 24 [Two] 26 [One] 25 [Three] 27 [One] 28 [Two] 29 [Three] 30
谁能帮助我纠正错误?
类似的 线程同步查询-同步三个线程以打印012012012012 .....无法正常工作
正如其他人已经提到的那样,CyclicBarrier并不是完全适合该任务的最佳工具。
我也同意,解决方案是将线程链接在一起,并始终让一个线程设置下一个线程。
这是使用信号量的实现:
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.Semaphore; public class PrintNumbersWithSemaphore implements Runnable { private final Semaphore previous; private final Semaphore next; private final int[] numbers; public PrintNumbersWithSemaphore(Semaphore previous, Semaphore next, int[] numbers) { this.previous = previous; this.next = next; this.numbers = numbers; } @Override public void run() { for (int i = 0; i < numbers.length; i++) { wait4Green(); System.out.println(numbers[i]); switchGreen4Next(); } } private void switchGreen4Next() { next.release(); } private void wait4Green() { try { previous.acquire(); } catch (InterruptedException e) { e.printStackTrace(); throw new RuntimeException(e); } } static public void main(String argv[]) throws InterruptedException, BrokenBarrierException { Semaphore sem1 = new Semaphore(1); Semaphore sem2 = new Semaphore(1); Semaphore sem3 = new Semaphore(1); sem1.acquire(); sem2.acquire(); sem3.acquire(); Thread t1 = new Thread(new PrintNumbersWithSemaphore(sem3, sem1, new int[] { 1, 4, 7 })); Thread t2 = new Thread(new PrintNumbersWithSemaphore(sem1, sem2, new int[] { 2, 5, 8 })); Thread t3 = new Thread(new PrintNumbersWithSemaphore(sem2, sem3, new int[] { 3, 6, 9 })); t1.start(); t2.start(); t3.start(); sem3.release(); t1.join(); t2.join(); t3.join(); } }
在我看来,使用CyclicBarrier实现起来非常麻烦:
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class PrintNumbersWithCyclicBarrier implements Runnable { private final CyclicBarrier previous; private final CyclicBarrier next; private final int[] numbers; public PrintNumbersWithCyclicBarrier(CyclicBarrier previous, CyclicBarrier next, int[] numbers) { this.previous = previous; this.next = next; this.numbers = numbers; } @Override public void run() { for (int i = 0; i < numbers.length; i++) { wait4Green(); System.out.println(numbers[i]); switchRed4Myself(); switchGreen4Next(); } } private void switchGreen4Next() { try { next.await(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } private void switchRed4Myself() { previous.reset(); } private void wait4Green() { try { previous.await(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } static public void main(String argv[]) throws InterruptedException, BrokenBarrierException { CyclicBarrier cb1 = new CyclicBarrier(2); CyclicBarrier cb2 = new CyclicBarrier(2); CyclicBarrier cb3 = new CyclicBarrier(2); Thread t1 = new Thread(new PrintNumbersWithCyclicBarrier(cb3, cb1, new int[] { 1, 4, 7 })); Thread t2 = new Thread(new PrintNumbersWithCyclicBarrier(cb1, cb2, new int[] { 2, 5, 8 })); Thread t3 = new Thread(new PrintNumbersWithCyclicBarrier(cb2, cb3, new int[] { 3, 6, 9 })); t1.start(); t2.start(); t3.start(); cb3.await(); t1.join(); t2.join(); t3.join(); } }