Java Concurrency - 浅析 CyclicBarrier 的用法
The Java concurrency API provides a synchronizing utility that allows the synchronization of two or more threads in a determined point. It's the CyclicBarrier class. This class is similar to the CountDownLatch class, but presents some differences that make them a more powerful class.
The CyclicBarrier class is initialized with an integer number, which is the number of threads that will be synchronized in a determined point. When one of those threads arrives to the determined point, it calls the await() method to wait for the other threads. When the thread calls that method, the CyclicBarrier class blocks the thread that is sleeping until the other threads arrive. When the last thread calls the await() method of the CyclicBarrier class, it wakes up all the threads that were waiting and continues with its job.
One interesting advantage of the CyclicBarrier class is that you can pass an additional Runnable object as an initialization parameter, and the CyclicBarrier class executes this object as a thread when all the threads have arrived to the common point. This characteristic makes this class adequate for the parallelization of tasks using the divide and conquer programming technique.
In this recipe, you will learn how to use the CyclicBarrier class to synchronize a set of threads in a determined point. You will also use a Runnable object that will execute after all the threads have arrived to that point. In the example, you will look for a number in a matrix of numbers. The matrix will be divided in subsets (using the divide and conquer technique), so each thread will look for the number in one subset. Once all the threads have finished their job, a final task will unify the results of them.
1. We're going to start the example by implementing two auxiliary classes. First, create a class named MatrixMock. This class will generate a random matrix of numbers between one and 10 where the threads are going to look for a number.
package com.packtpub.java7.concurrency.chapter3.recipe4.utils; import java.util.Random; /**
* This class generates a random matrix of integer numbers between 1 and 10
*
*/
public class MatrixMock { /**
* Bi-dimensional array with the random numbers
*/
private int data[][]; /**
* Constructor of the class. Generates the bi-dimensional array of numbers.
* While generates the array, it counts the times that appears the number we are going
* to look for so we can check that the CiclycBarrier class does a good job
* @param size Number of rows of the array
* @param length Number of columns of the array
* @param number Number we are going to look for
*/
public MatrixMock(int size, int length, int number){ int counter=0;
data=new int[size][length];
Random random=new Random();
for (int i=0; i<size; i++) {
for (int j=0; j<length; j++){
data[i][j]=random.nextInt(10);
if (data[i][j]==number){
counter++;
}
}
}
System.out.printf("Mock: There are %d ocurrences of number in generated data.\n",counter,number);
} /**
* This methods returns a row of the bi-dimensional array
* @param row the number of the row to return
* @return the selected row
*/
public int[] getRow(int row){
if ((row>=0)&&(row<data.length)){
return data[row];
}
return null;
} }
2. Implement a class named Results. This class will store, in an array, the number of occurrences of the searched number in each row of the matrix.
package com.packtpub.java7.concurrency.chapter3.recipe4.utils; /**
* This class is used to store the number of occurrences of the number
* we are looking for in each row of the bi-dimensional array
*
*/
public class Results { /**
* Array to store the number of occurrences of the number in each row of the array
*/
private int data[]; /**
* Constructor of the class. Initializes its attributes
* @param size Size of the array to store the results
*/
public Results(int size){
data=new int[size];
} /**
* Sets the value of one position in the array of results
* @param position Position in the array
* @param value Value to set in that position
*/
public void setData(int position, int value){
data[position]=value;
} /**
* Returns the array of results
* @return the array of results
*/
public int[] getData(){
return data;
}
}
3. Now that you have the auxiliary classes, it's time to implement the threads. First, implement the Searcher class. This class will look for a number in determined rows of the matrix of random numbers. Create a class named Searcher and specify that it implements the Runnable interface.
package com.packtpub.java7.concurrency.chapter3.recipe4.task; import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; import com.packtpub.java7.concurrency.chapter3.recipe4.utils.MatrixMock;
import com.packtpub.java7.concurrency.chapter3.recipe4.utils.Results; /**
* Class that search for a number in a set of rows of the bi-dimensional array
*
*/
public class Searcher implements Runnable { /**
* First row where look for
*/
private int firstRow; /**
* Last row where look for
*/
private int lastRow; /**
* Bi-dimensional array with the numbers
*/
private MatrixMock mock; /**
* Array to store the results
*/
private Results results; /**
* Number to look for
*/
private int number; /**
* CyclicBarrier to control the execution
*/
private final CyclicBarrier barrier; /**
* Constructor of the class. Initializes its attributes
* @param firstRow First row where look for
* @param lastRow Last row where fook for
* @param mock Object with the array of numbers
* @param results Array to store the results
* @param number Number to look for
* @param barrier CyclicBarrier to control the execution
*/
public Searcher(int firstRow, int lastRow, MatrixMock mock, Results results, int number, CyclicBarrier barrier){
this.firstRow=firstRow;
this.lastRow=lastRow;
this.mock=mock;
this.results=results;
this.number=number;
this.barrier=barrier;
} /**
* Main method of the searcher. Look for the number in a subset of rows. For each row, saves the
* number of occurrences of the number in the array of results
*/
@Override
public void run() {
int counter;
System.out.printf("%s: Processing lines from %d to %d.\n",Thread.currentThread().getName(),firstRow,lastRow);
for (int i=firstRow; i<lastRow; i++){
int row[]=mock.getRow(i);
counter=0;
for (int j=0; j<row.length; j++){
if (row[j]==number){
counter++;
}
}
results.setData(i, counter);
}
System.out.printf("%s: Lines processed.\n",Thread.currentThread().getName());
try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} }
4. Implement the class that calculates the total number of occurrences of the number in the matrix. It uses the Results object that stores the number of appearances of the number in each row of the matrix to make the calculation. Create a class named Grouper and specify that it implements the Runnable interface.
package com.packtpub.java7.concurrency.chapter3.recipe4.task; import com.packtpub.java7.concurrency.chapter3.recipe4.utils.Results; /**
* Group the results of each Searcher. Sum the values stored in the Results object
* An object of this class is executed automatically by the CyclicBarrier when
* all the Searchers finish its job
*/
public class Grouper implements Runnable { /**
* Results object with the occurrences of the number in each row
*/
private Results results; /**
* Constructor of the class. Initializes its attributes
* @param results Results object with the ocurrences of the number in each row
*/
public Grouper(Results results){
this.results=results;
} /**
* Main method of the Grouper. Sum the values stored in the Results object
*/
@Override
public void run() {
int finalResult=0;
System.out.printf("Grouper: Processing results...\n");
int data[]=results.getData();
for (int number:data){
finalResult+=number;
}
System.out.printf("Grouper: Total result: %d.\n",finalResult);
} }
5. Finally, implement the main class of the example by creating a class named Main.
package com.packtpub.java7.concurrency.chapter3.recipe4.core; import java.util.concurrent.CyclicBarrier; import com.packtpub.java7.concurrency.chapter3.recipe4.task.Grouper;
import com.packtpub.java7.concurrency.chapter3.recipe4.task.Searcher;
import com.packtpub.java7.concurrency.chapter3.recipe4.utils.MatrixMock;
import com.packtpub.java7.concurrency.chapter3.recipe4.utils.Results; /**
* Main class of the example
*
*/
public class Main { /**
* Main method of the example
* @param args
*/
public static void main(String[] args) { /*
* Initializes the bi-dimensional array of data
* 10000 rows
* 1000 numbers in each row
* Looking for number 5
*/
final int ROWS=10000;
final int NUMBERS=1000;
final int SEARCH=5;
final int PARTICIPANTS=5;
final int LINES_PARTICIPANT=2000;
MatrixMock mock=new MatrixMock(ROWS, NUMBERS,SEARCH); // Initializes the object for the results
Results results=new Results(ROWS); // Creates an Grouper object
Grouper grouper=new Grouper(results); // Creates the CyclicBarrier object. It has 5 participants and, when
// they finish, the CyclicBarrier will execute the grouper object
CyclicBarrier barrier=new CyclicBarrier(PARTICIPANTS,grouper); // Creates, initializes and starts 5 Searcher objects
Searcher searchers[]=new Searcher[PARTICIPANTS];
for (int i=0; i<PARTICIPANTS; i++){
searchers[i]=new Searcher(i*LINES_PARTICIPANT, (i*LINES_PARTICIPANT)+LINES_PARTICIPANT, mock, results, 5,barrier);
Thread thread=new Thread(searchers[i]);
thread.start();
}
System.out.printf("Main: The main thread has finished.\n");
} }
The problem resolved in the example is simple. We have a big matrix of random integer numbers and you want to know the total number of occurrences of a number in this matrix. To get a better performance, we use the divide and conquer technique. We divide the matrix in five subsets and use a thread to look for the number in each subset. These threads are objects of the Searcher class.
We use a CyclicBarrier object to synchronize the completion of the five threads and to execute the Grouper task to process the partial results, and calculate the final one.
As we mentioned earlier, the CyclicBarrier class has an internal counter to control how many threads have to arrive to the synchronization point. Each time a thread arrives to the synchronization point, it calls the await() method to notify the CyclicBarrier object that has arrived to its synchronization point. CyclicBarrier puts the thread to sleep until all the threads arrive to their synchronization point.
When all the threads have arrived to their synchronization point, the CyclicBarrier object wakes up all the threads that were waiting in the await() method and, optionally, creates a new thread that executes a Runnable object passed as the parameter in the construction of CyclicBarrier (in our case, a Grouper object) to do additional tasks.
The CyclicBarrier class has another version of the await() method:
await(long time, TimeUnit unit): The thread will be sleeping until it's interrupted; the internal counter of CyclicBarrier arrives to 0 or specified time passes. The TimeUnit class is an enumeration with the following constants: DAYS, HOURS, MICROSECONDS, MILLISECONDS, MINUTES, NANOSECONDS, and SECONDS.
This class also provides the getNumberWaiting() method that returns the number of threads that are blocked in the await() method, and the getParties() method that returns the number of tasks that are going to be synchronized with CyclicBarrier.
Resetting a CyclicBarrier object
The CyclicBarrier class has some points in common with the CountDownLatch class, but they also have some differences. One of the most important differences is that a CyclicBarrier object can be reset to its initial state, assigning to its internal counter the value with which it was initialized.
This reset operation can be done using the reset() method of the CyclicBarrier class. When this occurs, all the threads that were waiting in the await() method receive a BrokenBarrierException exception. This exception was processed in the example presented in this recipe by printing the stack trace, but in a more complex application, it could perform some other operation, such as restarting their execution or recovering their operation at the point it was interrupted.
Broken CyclicBarrier objects
A CyclicBarrier object can be in a special state denoted by broken. When there are various threads waiting in the await() method and one of them is interrupted, this thread receives an InterruptedException exception, but the other threads that were waiting receive a BrokenBarrierException exception and CyclicBarrier is placed in the broken state.
The CyclicBarrier class provides the isBroken() method, then returns true if the object is in the broken state; otherwise it returns false.
Java Concurrency - 浅析 CyclicBarrier 的用法的更多相关文章
- Java Concurrency - 浅析 CountDownLatch 的用法
The Java concurrency API provides a class that allows one or more threads to wait until a set of ope ...
- Java Concurrency - 浅析 Phaser 的用法
One of the most complex and powerful functionalities offered by the Java concurrency API is the abil ...
- 深入浅出 Java Concurrency (11): 锁机制 part 6 CyclicBarrier
如果说CountDownLatch是一次性的,那么CyclicBarrier正好可以循环使用.它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).所谓屏障 ...
- java CountDownLatch、CyclicBarrier和 Semaphore用法
一.CountDownLatch用法 CountDownLatch类位于java.util.concurrent中包下,利用它可以实现类似计数器的功能.比如有一个任务A,它要等待其他4个任务执行完毕之 ...
- 深入浅出 Java Concurrency (11): 锁机制 part 6 CyclicBarrier[转]
如果说CountDownLatch是一次性的,那么CyclicBarrier正好可以循环使用.它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).所谓屏障点就 ...
- 《Java Concurrency》读书笔记,使用JDK并发包构建程序
1. java.util.concurrent概述 JDK5.0以后的版本都引入了高级并发特性,大多数的特性在java.util.concurrent包中,是专门用于多线并发编程的,充分利用了现代多处 ...
- java多线程管理 concurrent包用法详解
我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,当然也有一些开源的框架提供了这些功能,但是这些依然没有JDK自带的功能使用起来方便.而当针对高质量 ...
- Java中的Socket的用法
Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...
- Java并发之CyclicBarrier 可重用同步工具类
package com.thread.test.thread; import java.util.Random; import java.util.concurrent.*; /** * Cyclic ...
随机推荐
- js两种创建对象方式
js创建方法的两种方式 <%@ page language="java" contentType="text/html; charset=ISO-8859-1&qu ...
- Android布局优化之include、merge、ViewStub的使用
本文针对include.merge.ViewStub三个标签如何在布局复用.有效减少布局层级以及如何可以按需加载三个方面进行介绍的. 复用布局可以帮助我们创建一些可以重复使用的复杂布局.这种方式也意味 ...
- zookeeper的C#Client
最近在搭一套soa, 服务使用java/scala 的finagle 协议使用thrift 然后 finagle默认服务端会是使用zookeeper作为节点存储.. 所以想要访问具体服务,需要先通过 ...
- phpStudy 2014的Apache虚拟主机配置
安装phpStudy直接百度下载,傻瓜式安装很简单,一直点击下一步即可,中途根据个人爱好设置WWW目录,我的设置在D盘根目录里. 打开虚拟主机配置,打开D:\phpStudy\Apache\conf下 ...
- QM课程01-功能概述
QM模块满足一个 CIQ 系统的下列功能: 一般功能 · 在物料主记录中集成QM检验数据 · 管理供应商和客户或销售部门的物料相关的质量信息 · 把质量特性和物料说明中的检验特性连接 · 管理中央凭证 ...
- exosip
exosip针对UA是对osip进行扩展,oSIP不提供不论什么高速产生请求消息和响应消息的方法,全部请求消息和响应消息的形成必须调用一组sip message api来手动组装完毕,所以作者在osi ...
- iOS开发——语法&高级Block练习
高级Block练习 一 .最简单的block使用 使用block的三个步骤:1.定义block变量 2.创建block代码块 3.调用block匿名函数 定义一个block的构成包括:返回值,bloc ...
- 机器学习经典算法详解及Python实现--基于SMO的SVM分类器
原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector ...
- PHP.8-HTML+CSS(二)-HTML详解
HTML+CSS HTML参考手册[http://www.w3school.com.cn/tags/index.asp] 0.HTML主体标记 代码分为三部分编写 <html> 是网页文件 ...
- [iOS 10 day by day] Day 1:开发 iMessage 的第三方插件
本文介绍了 iOS 10 的一个重要更新:Messages 应用支持第三方插件了.作者用一个小游戏作为例子,说明了插件开发从建工程开始,到绘制界面.收发消息的全过程. <iOS 10 day b ...