CyclicBarrier的使用

/ 多线程 / 没有评论 / 354浏览

CyclicBarrier和CountDownLatch一样在使用时也需要在构造方法中传递一个int类型的参数,但这个参数代表的含义和在使用上与CountDownLatch有所区别,这个参数代表的是拦截线程的数量,当线程调用CyclicBarrier中的await()方法时,就是告诉CyclicBarrier我已经拦截了当前线程,也就是此时调用await()方法的线程将被阻塞,线程中await()方法后面的代码将不会执行,当前线程会一直等待,一到调用await()方法的线程数量与CyclicBarrier构造方法中参数的数量一致时,线程才会重新执行。下面我们看一下简单的例子来演示一下CyclicBarrier的使用。

public class Test {
public static void main(String[] args) throws InterruptedException {
CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(String.format("开始: %s", Thread.currentThread().getName()));
for (int i = 10; i > 0; i--) {
System.out.println(String.format("计时:%s\tthread: %s", i, Thread.currentThread().getName()));
Thread.sleep(1000);
}
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(String.format("任务: %s", Thread.currentThread().getName()));
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(String.format("开始: %s", Thread.currentThread().getName()));
for (int i = 5; i > 0; i--) {
System.out.println(String.format("计时:%s\tthread: %s", i, Thread.currentThread().getName()));
Thread.sleep(1000);
}
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(String.format("任务: %s", Thread.currentThread().getName()));
}
});
thread1.start();
thread2.start();
System.out.println(String.format("任务: %s", Thread.currentThread().getName()));
}
}
开始: Thread-1
任务: main
开始: Thread-0
计时:5	thread: Thread-1
计时:10	thread: Thread-0
计时:9	thread: Thread-0
计时:4	thread: Thread-1
计时:8	thread: Thread-0
计时:3	thread: Thread-1
计时:7	thread: Thread-0
计时:2	thread: Thread-1
计时:6	thread: Thread-0
计时:1	thread: Thread-1
计时:5	thread: Thread-0
计时:4	thread: Thread-0
计时:3	thread: Thread-0
计时:2	thread: Thread-0
计时:1	thread: Thread-0
任务: Thread-1
任务: Thread-0

下面我们详细分析一下输出的信息。我们在CyclicBarrier构造方法中传递的参数是2也就是说它要拦截2个线程的await()方法后才会执行await()方法后面的逻辑。所以在调用await()方法之前线程是不会阻塞的。所以会出输出开始、计时等信息,我们会发现当线程Thread-1已经执行完循环任务时,并没有马上输出await()方法后面的代码,而是此线程阻塞了,原因是Thread-0还没有实现完,它还没有执行await()方法,也就是说拦截的线程数量还没有达到CyclicBarrier构造方法中传递数量,所以线程Thread-1就会一直阻塞直到Thread-0执行完循环并执行await()方法时,此时拦截的线程数量已经等于构造方法中的参数了,所以线程Thread-1才会恢复执行。这就是CyclicBarrier的使用。

CyclicBarrier与CountDownLatch的区别:

CyclicBarrier还提供了另一个构造方法除了传递int类型的参数外,还可以传递一个Runnable类型。它的目的是,当线程的拦截的数量与构造方法的参数相等时,优先执行构造方法里的任务,然后在执行每个线程中await()方法后面的代码。

public class Test {
public static void main(String[] args) throws InterruptedException {
CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
@Override
public void run() {
System.out.println(String.format("拦截: %s", Thread.currentThread().getName()));
}
});
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(String.format("开始: %s", Thread.currentThread().getName()));
for (int i = 10; i > 0; i--) {
System.out.println(String.format("计时:%s\tthread: %s", i, Thread.currentThread().getName()));
Thread.sleep(1000);
}
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(String.format("任务: %s", Thread.currentThread().getName()));
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(String.format("开始: %s", Thread.currentThread().getName()));
for (int i = 5; i > 0; i--) {
System.out.println(String.format("计时:%s\tthread: %s", i, Thread.currentThread().getName()));
Thread.sleep(1000);
}
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(String.format("任务: %s", Thread.currentThread().getName()));
}
});
thread1.start();
thread2.start();
System.out.println(String.format("任务: %s", Thread.currentThread().getName()));
}
}
开始: Thread-0
开始: Thread-1
计时:10	thread: Thread-0
计时:5	thread: Thread-1
任务: main
计时:4	thread: Thread-1
计时:9	thread: Thread-0
计时:8	thread: Thread-0
计时:3	thread: Thread-1
计时:7	thread: Thread-0
计时:2	thread: Thread-1
计时:6	thread: Thread-0
计时:1	thread: Thread-1
计时:5	thread: Thread-0
计时:4	thread: Thread-0
计时:3	thread: Thread-0
计时:2	thread: Thread-0
计时:1	thread: Thread-0
拦截: Thread-0
任务: Thread-0
任务: Thread-1