java并行程序设计_Java:并行编程及同步使用方法

知道java可以使用java.util.concurrent包下的

CountDownLatch

ExecutorService

Future

Callable

实现并行编程,并在并行线程同步时,用起来十分简单的一种 。

实现原理:

1、CountDownLatch 统计并行线程完成数,并提供了await()方法,实现等待所有并行线程完成,或者指定最大等待时间。

2、ExecutorService提供了execute(Callable)执行线程方法,还提供了submit(Callable)提交线程。

3、Future接受实现Callable接口的(可执行线程)返回值,接受Executors.submit(Callable)返回值。而且Future提供get()取回并行子线程返回的参数,还可以给get指定过期时间。

想到Concurrent,就能想到c#中,命名空间System.Collection,Concurrent,在该命名空间下提供了一些线程安全的集合类。

代码示例:

13968cd9842e37950cfcc0039d57df10.png

MyTaskResult.java

packagecom.dx.testparallel;public classMyTaskResult {privateString name;publicMyTaskResult(String name){this.name=name;

}publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}

}

TaskItem.java

packagecom.dx.testparallel;public classTaskItem {private intid;privateString name;public TaskItem(intid,String name){this.id=id;this.name=name;

}public intgetId() {returnid;

}public void setId(intid) {this.id =id;

}publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}

}

MyTask.java

packagecom.dx.testparallel;importjava.util.concurrent.Callable;importjava.util.concurrent.CountDownLatch;public class MyTask implements Callable{private finalTaskItem taskItem;private finalCountDownLatch threadsSignal;publicMyTask(CountDownLatch threadsSignal,TaskItem taskItem) {this.threadsSignal=threadsSignal;this.taskItem=taskItem;

}

@Overridepublic MyTaskResult call() throwsException {

MyTaskResult result=new MyTaskResult(this.taskItem.getName());//核心处理逻辑处理

Thread.sleep(2000);

System.out.println("task id:" + taskItem.getId() +" >>>>等待結束");

System.out.println("task id:" + taskItem.getId() + " >>>>线程名称:" + Thread.currentThread().getName() + "结束. 还有" + threadsSignal.getCount() + " 个线程");//必须等核心处理逻辑处理完成后才可以减1

this.threadsSignal.countDown();returnresult;

}

}

Main.java

packagecom.dx.testparallel;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.CountDownLatch;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Future;public classMain {public static void main(String[] args) throwsInterruptedException {

List taskItems=new ArrayList();for(int i=0;i<20;i++){

taskItems.add(new TaskItem(i, "task "+i));

}

CountDownLatch threadsSignal= newCountDownLatch(taskItems.size());

ExecutorService executor=Executors.newFixedThreadPool(taskItems.size());

List> resultLazyItems=new ArrayList>();

System.out.println("主線程開始進入並行任務提交");for(TaskItem taskItem : taskItems) {//使用future存储子线程执行后返回结果,必须在所有子线程都完成后才可以使用get();//如果在这里使用get(),会造成等待同步。

Future future = executor.submit(newMyTask(threadsSignal,taskItem));

resultLazyItems.add(future);

}

System.out.println("主線程開始走出並行任務提交");

System.out.println("主線程進入等待階段(等待所有并行子线程任务完成)。。。。。");//等待所有并行子线程任务完成。

threadsSignal.await();//并不是终止线程的运行,而是禁止在这个Executor中添加新的任务

executor.shutdown();

System.out.println("主線程走出等待階段(等待所有并行子线程任务完成)。。。。。");for(Futurefuture :resultLazyItems){try{

MyTaskResult result=future.get();

System.out.println(result.getName());

}catch(ExecutionException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

运行结果:

主線程開始進入並行任務提交

主線程開始走出並行任務提交

主線程進入等待階段(等待所有并行子线程任务完成)。。。。。

task id:0 >>>>等待結束

task id:6 >>>>等待結束

task id:8 >>>>等待結束

task id:3 >>>>等待結束

task id:4 >>>>等待結束

task id:2 >>>>等待結束

task id:2 >>>>线程名称:pool-1-thread-3结束. 还有20 个线程

task id:5 >>>>等待結束

task id:1 >>>>等待結束

task id:7 >>>>等待結束

task id:1 >>>>线程名称:pool-1-thread-2结束. 还有19 个线程

task id:5 >>>>线程名称:pool-1-thread-6结束. 还有19 个线程

task id:4 >>>>线程名称:pool-1-thread-5结束. 还有20 个线程

task id:19 >>>>等待結束

task id:10 >>>>等待結束

task id:18 >>>>等待結束

task id:18 >>>>线程名称:pool-1-thread-19结束. 还有16 个线程

task id:3 >>>>线程名称:pool-1-thread-4结束. 还有20 个线程

task id:8 >>>>线程名称:pool-1-thread-9结束. 还有20 个线程

task id:6 >>>>线程名称:pool-1-thread-7结束. 还有20 个线程

task id:0 >>>>线程名称:pool-1-thread-1结束. 还有20 个线程

task id:10 >>>>线程名称:pool-1-thread-11结束. 还有16 个线程

task id:19 >>>>线程名称:pool-1-thread-20结束. 还有16 个线程

task id:12 >>>>等待結束

task id:17 >>>>等待結束

task id:17 >>>>线程名称:pool-1-thread-18结束. 还有9 个线程

task id:11 >>>>等待結束

task id:11 >>>>线程名称:pool-1-thread-12结束. 还有8 个线程

task id:14 >>>>等待結束

task id:14 >>>>线程名称:pool-1-thread-15结束. 还有7 个线程

task id:16 >>>>等待結束

task id:16 >>>>线程名称:pool-1-thread-17结束. 还有6 个线程

task id:15 >>>>等待結束

task id:9 >>>>等待結束

task id:13 >>>>等待結束

task id:7 >>>>线程名称:pool-1-thread-8结束. 还有19 个线程

task id:13 >>>>线程名称:pool-1-thread-14结束. 还有5 个线程

task id:9 >>>>线程名称:pool-1-thread-10结束. 还有5 个线程

task id:15 >>>>线程名称:pool-1-thread-16结束. 还有5 个线程

task id:12 >>>>线程名称:pool-1-thread-13结束. 还有9 个线程

主線程走出等待階段(等待所有并行子线程任务完成)。。。。。

task 0

task 1

task 2

task 3

task 4

task 5

task 6

task 7

task 8

task 9

task 10

task 11

task 12

task 13

task 14

task 15

task 16

task 17

task 18

task 19

注释以下代码:

//Thread.sleep(2000);//System.out.println("task id:" + taskItem.getId() +" >>>>等待結束");

之后运行结果:

主線程開始進入並行任務提交

task id:1 >>>>线程名称:pool-1-thread-2结束. 还有20 个线程

task id:2 >>>>线程名称:pool-1-thread-3结束. 还有20 个线程

task id:3 >>>>线程名称:pool-1-thread-4结束. 还有20 个线程

task id:4 >>>>线程名称:pool-1-thread-5结束. 还有19 个线程

task id:5 >>>>线程名称:pool-1-thread-6结束. 还有19 个线程

task id:8 >>>>线程名称:pool-1-thread-9结束. 还有15 个线程

task id:0 >>>>线程名称:pool-1-thread-1结束. 还有14 个线程

task id:9 >>>>线程名称:pool-1-thread-10结束. 还有13 个线程

task id:7 >>>>线程名称:pool-1-thread-8结束. 还有12 个线程

task id:6 >>>>线程名称:pool-1-thread-7结束. 还有14 个线程

task id:10 >>>>线程名称:pool-1-thread-11结束. 还有10 个线程

task id:11 >>>>线程名称:pool-1-thread-12结束. 还有9 个线程

task id:12 >>>>线程名称:pool-1-thread-13结束. 还有8 个线程

task id:13 >>>>线程名称:pool-1-thread-14结束. 还有7 个线程

task id:14 >>>>线程名称:pool-1-thread-15结束. 还有6 个线程

task id:15 >>>>线程名称:pool-1-thread-16结束. 还有5 个线程

task id:16 >>>>线程名称:pool-1-thread-17结束. 还有4 个线程

task id:17 >>>>线程名称:pool-1-thread-18结束. 还有3 个线程

task id:18 >>>>线程名称:pool-1-thread-19结束. 还有2 个线程

主線程開始走出並行任務提交

主線程進入等待階段(等待所有并行子线程任务完成)。。。。。

task id:19 >>>>线程名称:pool-1-thread-20结束. 还有1 个线程

主線程走出等待階段(等待所有并行子线程任务完成)。。。。。

task0task1task2task3task4task5task6task7task8task9task10task11task12task13task14task15task16task17task18task19

项目中应用:

定义可执行线程类:

public class UploadFileToTask implements Callable{private finalTask_UploadFileToTaskItem taskItem;private final Log log = LogHelper.getInstance(ImportMain.class);private finalCountDownLatch threadsSignal;private final HDFSUtil hdfsUtil = newHDFSUtil();private final static String HADOOP_HDFS_PATH =HdfsConfiguration.getHdfsUrl();publicUploadFileToTask(CountDownLatch threadsSignal ,Task_UploadFileToTaskItem taskItem){this.taskItem=taskItem;this.threadsSignal=threadsSignal;

}

@Overridepublic UploadFileToTaskResult call() throwsException {

String area=taskItem.getArea();

String fileGenerateDate=taskItem.getFileGenerateDate();

String manufacturer=taskItem.getManufacturer();

String eNodeBId=taskItem.geteNodeBId();

String filePath=taskItem.getFilePath();

FileType fileType=taskItem.getFileType();

TaskStatus taskStatus=TaskStatus.Success;//不确定该FileSystem是否是线程安全的,故在每一个thread初始化一次。

Configuration conf = newConfiguration();

Path dstPath= newPath(HADOOP_HDFS_PATH);

FileSystem hdfs=dstPath.getFileSystem(conf);//核心代码。。。//上传MR文件//上传Signal文件//如果文件路径不为空,就开始上传文件到hdfs

if(uploadFilePath.length()>0){if (!hdfsUtil.uploadFileToHdfs(hdfs, filePath, uploadFilePath)) {

taskStatus=TaskStatus.Fail;

}

}

TaskGroupInfo taskGroupInfo= newTaskGroupInfo();

taskGroupInfo.setArea(area);

taskGroupInfo.setManufacturer(manufacturer);

taskGroupInfo.setFileGenerateDate(fileGenerateDate);

taskGroupInfo.setFileType(fileType);

String key= String.format("%s,%s,%s,%s", taskGroupInfo.getArea(), taskGroupInfo.getManufacturer(), taskGroupInfo.getFileGenerateDate(), String.valueOf(taskGroupInfo.getFileType().getValue()));

UploadFileToTaskResult result=newUploadFileToTaskResult();//填充返回值

result.setStatus(taskStatus);

result.setTaskGroupInfo(taskGroupInfo);

result.setTaskGroupkey(key);

result.setTaskOID(taskItem.getOid());

System.out.println("task id:" + taskItem.getOid() + " >>>>线程名称:" + Thread.currentThread().getName() + "结束. 还有" + threadsSignal.getCount() + " 个线程");//必须等核心处理逻辑处理完成后才可以减1

this.threadsSignal.countDown();returnresult;

}

}

实现并行线程同步核心代码:

//获取当前节点带执行任务

ArrayList taskItems = uploadFileToTaskItemDao.getTopNTodoTaskItems(this.computeNode.getId(),Configuration.getTaskCount());//批量修改任务状态为正在处理状态(doing)。

log.info("Start:>>>>>>batch modify task status(doing)>>>>>>");log.info("Over:>>>>>>batch modify task status(doing)>>>>>>");//批量处理上传任务(上传文件到)

log.info("Start:>>>>>>each process task(upload to)>>>>>>");

CountDownLatch threadsSignal= newCountDownLatch(taskItems.size());

ExecutorService executor=Executors.newFixedThreadPool(taskItems.size());

List> resultLazyItems=new ArrayList>();for(Task_UploadFileToTaskItem taskItem : taskItems) {//使用future存储子线程执行后返回结果,必须在所有子线程都完成后才可以使用get();//如果在这里使用get(),会造成等待同步。

Future future = executor.submit(newUploadFileToTask(threadsSignal,taskItem));

resultLazyItems.add(future);

}//等待所有并行子线程任务完成。

threadsSignal.await();

executor.shutdown();//并不是终止线程的运行,而是禁止在这个Executor中添加新的任务

log.info("Over:>>>>>>each process task(upload to)>>>>>>");//批量修改任务处理状态

Map taskGroupItems=new HashMap();

Map successTaskItems = new HashMap();

Map failTaskItems = new HashMap();for(Futurefuture :resultLazyItems){

UploadFileToTaskResult result=future.get();if(!taskGroupItems.containsKey(result.getTaskGroupkey())){

taskGroupItems.put(result.getTaskGroupkey(),result.getTaskGroupInfo());

}if(result.getStatus()==TaskStatus.Success){

successTaskItems.put(result.getTaskOID(),result.getStatus());

}else{

failTaskItems.put(result.getTaskOID(),result.getStatus());

}

}

参考资料:

http://blog.csdn.net/wangmuming/article/details/19832865

http://www.importnew.com/21312.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值