Bootstrap

Java并发利器:CyclicBarrier的使用与实例

在多线程编程中,线程之间的协同工作是一个常见的需求。Java提供了多种工具来帮助我们实现线程的同步,其中CyclicBarrier是一个非常实用的类。它允许一组线程(称为参与者)在某个公共屏障点相互等待,直到所有线程都到达该点后才继续执行。与CountDownLatch类似,但CyclicBarrier可以重复使用,而CountDownLatch的计数器一旦归零则无法重置。接下来,我们将通过一个具体的例子来深入理解CyclicBarrier的使用。
CyclicBarrier的基本概念
CyclicBarrier初始化时需要指定一个计数器值(即参与者数量)。当调用await()方法时,计数器会递减。当计数器值为零时,表示所有线程都已到达屏障点,此时所有线程可以继续执行。此外,CyclicBarrier还提供了一个带有超时时间的await(long timeout, TimeUnit unit)方法,允许线程在等待时设置最大等待时间。
与CountDownLatch不同,CyclicBarrier的await()方法不仅会阻塞线程,还会减少计数器的值。而且,CyclicBarrier是可重用的,这意味着一旦所有线程通过屏障点后,计数器会自动重置为初始值,线程可以再次使用它。CyclicBarrier内部是同步的,因此可以安全地被多个线程使用。
示例:使用CyclicBarrier实现线程同步
为了更好地理解CyclicBarrier的工作方式,我们通过一个简单的GUI示例来展示它的使用。在这个例子中,我们创建了一个包含多个进度条的窗口,每个进度条由一个线程更新。当进度条的值达到某个特定值时,线程会在屏障点等待,直到所有线程都到达该点后才继续执行。
以下是完整的代码实现:
java复制
import javax.swing.;
import java.awt.
;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
private static final int THREAD_COUNT = 4;

public static void main(String[] args) {
    CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT);
    JFrame frame = createFrame();
    frame.setLayout(new FlowLayout(FlowLayout.LEFT));
    for (int i = 1; i <= THREAD_COUNT; i++) {
        ProgressThread progressThread = new ProgressThread(barrier, i * 10);
        frame.add(progressThread.getProgressComponent());
        progressThread.start();
    }
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
}

private static JFrame createFrame() {
    try {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (Exception e) {
        e.printStackTrace();
    }
    JFrame frame = new JFrame("Java CyclicBarrier Example");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(new Dimension(ProgressThread.PROGRESS_WIDTH, 170));
    return frame;
}

}

class ProgressThread extends Thread {
public static final int PROGRESS_WIDTH = 350;
private static final int CATCH_UP_MULTIPLE = 25;
private final JProgressBar progressBar;
private final CyclicBarrier barrier;
private final int slowness;

public ProgressThread(CyclicBarrier barrier, int slowness) {
    this.barrier = barrier;
    this.slowness = slowness;
    progressBar = new JProgressBar();
    progressBar.setPreferredSize(new Dimension(PROGRESS_WIDTH - 30, 25));
    progressBar.setStringPainted(true);
}

JComponent getProgressComponent() {
    return progressBar;
}

@Override
public void run() {
    int c = 0;
    boolean reversed = false;
    while (true) {
        progressBar.setValue(reversed ? --c : ++c);
        if (c == 100) {
            reversed = true;
        } else if (c == 0) {
            reversed = false;
        }
        try {
            Thread.sleep(slowness);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (c % CATCH_UP_MULTIPLE == 0) {
            try {
                barrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

}
示例解析
在上述代码中,我们创建了一个包含4个线程的程序,每个线程负责更新一个进度条。每个线程在进度条值达到25的倍数时调用barrier.await(),等待其他线程也到达该点。一旦所有线程都调用了await()方法,计数器归零,线程们继续执行。
这种机制非常适合需要多个线程在某个点同步的场景,例如在多线程任务中,每个线程完成一部分工作后需要等待其他线程完成,然后一起进入下一个阶段。
总结
CyclicBarrier是Java并发工具包中一个非常强大的类,它允许一组线程在某个屏障点相互等待,直到所有线程都到达该点后才继续执行。与CountDownLatch相比,CyclicBarrier可以重复使用,并且在内部同步机制的保护下,可以安全地被多个线程使用。通过本文的示例,我们可以看到CyclicBarrier在多线程同步中的强大功能,它可以帮助我们更高效地实现线程间的协作。

;