在多线程编程中,线程之间的协同工作是一个常见的需求。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在多线程同步中的强大功能,它可以帮助我们更高效地实现线程间的协作。