经验分享:深入理解Java 并行编程

中国IT实验室 发表于:12年10月23日 14:42 [转载] 中国IT实验室

  • 分享:
[导读]深入理解Java 并行编程--用java.util.concurrent的High Level API编程

概述

基于Thread类和Runnable接口编程很容易实现基本的并行编程任务,但实现复杂的并行程序就会比较困难,因为要详细考虑资源的同步访问以及设计必要数据结构支持同步访问。从Java5后,Java平台提供了java.util.concurrent包以及HighLevelAPI简化并行编程模型,并提供了很多支持同步访问数据结构满足编程需要。具体来讲,该HighLevelAPI提供了以下内容,在后续段落我将分别介绍。

Lock(锁对象):相对与Thread模型的隐式的锁对象,Lock提供了显式的锁操作从而简化应用程序。

Executors:提供了一组HighLevelAPI用来执行和管理并行任务。

ConcurrentCollections(并行集合):包含了一组支持并行处理的数据结构,大大简化了并行编程难度。

AtomicVariables(原子变量):减少了同步操作并且避免数据不一致问题。

Fork/Join框架:提供了进程操作的支持。

Lock(锁对象)

Lock在java.util.concurrent.locks包里面,是一个用来同步对共享资源的访问的工具,其实际效果和Synchronize 比较像。Synchronize用起来很容易,但是Synchroize也有一些限制:当Synchronize以一定顺序获得多个锁的时候,必须以相反的顺序释放锁,并且必须在与获得锁相同的代码scope中释放锁。Lock则完全克服了上述限制:能够以任意的顺序获得和释放所,而且不需要收到代码 scope的限制。使用Lock也很简单,通常会使用以下代码使用Lock:

方式一:

Lockl=…;

l.lock();

try{

//访问共享资源

}finally{

l.unlock()

}

方式二:

Lockl=…;

if(l.tryLock()){

try{

//访问共享资源

finally{

l.unlock();

}

else{

//没能够获得锁,做其它事情

}

ConcurrentCollections(并行集合):

java.util.concurrent包还提供了一系列的数据结构,使得并行程序的开发人员可以更少地关注同步操作。

BlockingQueue是一个支持先入先出(First-in-first-out,FIFO)的数据结构,对于队列的push和poll等操作都采取阻塞的方式保证只有在获得资源锁的时候才可以执行。

ConcurrentMap是一个跟Map类似的存储key/value映射的数据结构,该数据结构保证了Map操作的原子性。

ConcurrentNavigableMap是一个跟TreeMap类似的数据结构,允许基于key进行树状遍历。

下面给出BlockingQueue的基本用法:

BlockingQueuequeue=newSynchronousQueue();

queue.put(“helloworld”);

queue.poll();//返回helloworld

AtomicVariables(原子变量):

java.util.concurrent.atomic包提供了一些数据结构用来支持对变量的原子操作,这些数据结构都必须支持get和set方法从而支持对变量的读写。下面是一个例子来证明如何使用AtomicInteger的。

importjava.util.concurrent.atomic.AtomicInteger;

classAtomicCounter{

privateAtomicIntegerc=newAtomicInteger(0);

publicvoidincrement(){

c.incrementAndGet();

}

publicvoiddecrement(){

c.decrementAndGet();

}

publicintvalue(){

returnc.get();

}

}

Fork/Join框架

Fork/Join是自JDK7以后才有的对ExecutorService接口的一个实现,用来支持在多核处理器上进行多进程操作。该框架适合于那些能够被递归地分解成更小任务的任务。该框架最牛的地方在于采用了work-stealing算法,也就是空闲的worker可以从繁忙的worker那里偷(steal)任务过来执行,从而充分利用计算资源使得任务执行更快。

Fork/Join的核心是ForkJoinPool这个类,它是AbstractExecutorService的子类并实现了work-stealing算法,其被用来执行ForkJoinTask.

ForkJoinTask实现类有RecursiveTask核ResursiveAction,通常实现的逻辑为:

if(当前任务足够小)

直接执行任务

else

将当前任务分为更小的两个任务

执行这两个更小的任务并等待结果

下面的代码示意对Fork/Join框架的使用:

public class MyListPrinter extends RecursiveAction {

private List task;

public MyListPrinter(List list)

task = list;

}

protected void printList() {

// 遍历并打印task中的元素

}

protected void compute() {

if (task.length() <= 1000) {

printList();

} else{

List first_half_list = ……

List second_half_list = ……

MyListPrinter printer1 = new MyListPrinter(first_half_list);

MyListPrinter printer2 = new MyListPrinter(second_half_list);

invokeAll(printer1, printer2);

}

}

}

MyListPrinterprinter=newMyListPrinter(aHugeList);

ForkJoinPoolpool=newForkJoinPool();

pool.invoke(printer);

[责任编辑:韩蕊]
Ruby
SAP分享了多年来对企业运营变革的洞察,以及SAP Business Suite powered by HANA如何推动企业在对业务影响最小的情况下向实时企业转型,从而帮助企业实现更睿智的业务创新、更快速的业务流程和更简化的业务交互。发布会现场,SAP公司宣布,中国最大的瓶装水生产商——农夫山泉成为基于 SAP HANA 的SAP Business Suite在中国的首家客户。
官方微信
weixin
精彩专题更多
存储风云榜”是由DOIT传媒主办的年度大型活动。回顾2014年,存储作为IT系统架构中最基础的元素,已经成为了推动信息产业发展的核心动力,存储产业的发展迈向成熟,数据经济的概念顺势而为的提出。
华为OceanStor V3系列存储系统是面向企业级应用的新一代统一存储产品。在功能、性能、效率、可靠性和易用性上都达到业界领先水平,很好的满足了大型数据库OLTP/OLAP、文件共享、云计算等各种应用下的数据存储需求。
联想携ThinkServer+System+七大行业解决方案惊艳第十六届高交会
 

公司简介 | 媒体优势 | 广告服务 | 客户寄语 | DOIT历程 | 诚聘英才 | 联系我们 | 会员注册 | 订阅中心

Copyright © 2013 DOIT Media, All rights Reserved. 北京楚科信息技术有限公司 版权所有.