在JDK1.5之前,对高质量Java多线程并发程序设计时,为防止程序崩掉等现象的出现,比如使用wait()、notify()和synchronized等,需要考虑性能、死锁、公平性、资源管理以及如何避免线程安全性方面带来的危害等诸多因素,通常会采用一些较为复杂的安全策略,加重了程序员的开发负担。在JDK1.5出现之后,大牛Doug Lee编写了java.util.concurrent java并发工具包,开发者利用此包,可大大提高并发程序的开发效率,并且能有效防止资源竞争、状态一致和避免死锁。java.util.concurrent包分成了三个部分,分别是java.util.concurrent、java.util.concurrent.atomic和java.util.concurrent.locks。内容涵盖了并发集合类、线程池机制、同步互斥机制、线程安全的变量更新工具类、锁等常用工具。
1) java.util.concurren:其主要的接口和类有Executor、Executors、ExecutorService、Callable、Future和BlockingQueue,这6个接口和类可如下理解:
﹒Executor:具体Runnable任务的执行者;
﹒Executors:提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口;
﹒ExecutorService:扩展了Executor并添加了一些生命周期管理的方法。一个ExecutorService的生命周期有三种状态:运行、关闭和终止。ExecutorService创建时处于运行状态,当调用ExecutorService.shutdown()后处于关闭状态,所有已添加的任务执行完毕后ExecutorService处于终止状态;
﹒Future:是与Runnable,Callable进行交互的接口,比如一个线程执行结束后取返回的结果等等,还提供了cancel终止线程;
﹒BlockingQueue:阻塞队列。
表格所示为代码示例:
package com.thread.test.concurent;
import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.RejectedExecutionException;
import junit.framework.TestCase;
/** * * <p>Description:concurrent包Executors,ExecutorService等的简单应用Case</p> * @author 乡台瑞猿 * @version $Id: ExecutorTest.java,v 0.1 Feb 21, 2010 4:09:59 PM Exp $ */ public class ExecutorTest extends TestCase{
/** * <p>Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。 * Executor.execute(Runnalbe),Executor在执行时使用内部的线程池完成操作</p> * @author 乡台瑞猿 * @date Feb 21, 2010 4:12:28 PM */ public void ftestExecutor(){ Executor executor = Executors.newFixedThreadPool(10); System.out.println(); System.out.println("Test case: "+this.getName()); Runnable task = new Runnable() { public void run() { System.out.println("Exceutor exec runable."); } }; executor.execute(task);
/****************执行结果**************** *Test case: testExecutor *Exceutor exec runable. * *************************************/ }
/** * <p>扩展了Executor并添加了一些生命周期管理的方法。一个ExecutorService的生命周期有三种状态: * 运行、关闭和终止。ExecutorService创建时处于运行状态,当调用ExecutorService.shutdown() * 后处于关闭状态,所有已添加的任务执行完毕后ExecutorService处于终止状态</p> * @author 乡台瑞猿 * @date Feb 21, 2010 4:44:41 PM */ public void ftestExecutorService(){ Executor executor = Executors.newFixedThreadPool(10); ExecutorService executorService = (ExecutorService) executor; // System.out.println(); System.out.println("Test case: "+this.getName()); Runnable task = new Runnable() { public void run() { System.out.println("ExecutorService exec runable."); } }; // System.out.println("executorService.isShutdown() = "+executorService.isShutdown()); System.out.println("executorService.isTerminated() = "+executorService.isTerminated()); while (!executorService.isShutdown()) { try { executorService.execute(task); executorService.shutdown(); } catch (RejectedExecutionException ignored) { } } System.out.println("executorService.isShutdown() = "+executorService.isShutdown()); System.out.println("executorService.isTerminated() = "+executorService.isTerminated());
/****************执行结果**************** *Test case: testExecutorService *executorService.isShutdown() = false *executorService.isTerminated() = false *executorService.isShutdown() = true *executorService.isTerminated() = false *ExecutorService exec runable. *或者 *Test case: testExecutorService *executorService.isShutdown() = false *executorService.isTerminated() = false *ExecutorService exec runable. *executorService.isShutdown() = true *executorService.isTerminated() = true * *************************************/ //从中可以看出executorService等所有已添加的任务执行完毕之后才Terminated }
/** * * <p>ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。 * 如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。</p> * @author 乡台瑞猿 * @date Feb 21, 2010 7:05:05 PM */ public void testCallableFuture(){ List<Future<Long>> tasks = new ArrayList<Future<Long>>(); int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11 }; int cpuCounts = Runtime.getRuntime().availableProcessors(); //cpu 核数 Executor executor = Executors.newFixedThreadPool(cpuCounts); ExecutorService executorService = (ExecutorService) executor; // 根据CPU核心个数拆分任务,创建FutureTask并提交到Executor for (int i = 0; i < cpuCounts; i++) { int increment = numbers.length / cpuCounts + 1; int start = increment * i; int end = increment * i + increment; end = (end > numbers.length)?numbers.length:end; //new 一个 SumCalculator实例 SumCalculator subCalc = new SumCalculator(numbers, start, end); FutureTask<Long> task = new FutureTask<Long>(subCalc); tasks.add(task); if (!executorService.isShutdown()) { //Submits a Runnable task for execution and returns a Future representing that task executorService.submit(task); } }
Long result = 0l; for (Future<Long> task : tasks) { try { // 如果计算未完成则阻塞 Long subSum = task.get(); result += subSum; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } //输出计算结果,1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11的求和 System.out.println("result:"+result); }
// 内部类,必须要实现call()函数 class SumCalculator implements Callable<Long> { private int[] numbers; private int start; private int end; public SumCalculator(final int[] numbers, int start, int end) { this.numbers = numbers; this.start = start; this.end = end; } public Long call() throws Exception { Long sum = 0l; for (int i = start; i < end; i++) { sum += numbers[i]; } return sum; } } } |
2) java.util.concurrent.atomic,原子变量
在 JDK 5.0 之前,如果不使用本机代码,就不能用 Java 语言编写无等待、无锁定的算法。在 java.util.concurrent.atomic 包中添加原子变量之后,这种情况才发生了改变。所有原子变量类都公开比较并设置原语(与比较并交换类似),这些原语都是使用平台上可用的最快本机结构(比较并交换、加载链接/条件存储,最坏的情况下是旋转锁)来实现的。 java.util.concurrent.atomic 包中提供了原子变量的 9 种风格( AtomicInteger; AtomicLong; AtomicReference; AtomicBoolean;原子整型;长型;引用;及原子标记引用和戳记引用类的数组形式,其原子地更新一对值)。
原子变量类可以认为是 volatile 变量的泛化,它扩展了可变变量的概念,来支持原子条件的比较并设置更新。读取和写入原子变量与读取和写入对可变变量的访问具有相同的存取语义。原子变量的操作会变为平台提供的用于并发访问的硬件原语,比如比较并交换,因而竞争的操作就更少,吞吐量更高。
http://www.ibm.com/developerworks/cn/java/j-jtp11234/index.html,该文很好地介绍了atomic,流行的原子。
3) java.util.concurrent.locks
java.util.concurrent.locks中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 Java 类,而不是作为语言的特性来实现。这就为 Lock 的多种实现留下了空间,各种实现可能有不同的调度算法、性能特性或者锁定语义。关于jdk同步包锁机制详细讨论将会在下一篇博文“java多线程编程要点——控制单元”中展开。