参考博文:http://www.cnblogs.com/sarafill/archive/2011/05/18/2049461.html
http://blog.csdn.net/wulei_longhe/article/details/30032031
JDK 5.0 中的并发改进可以分为三组:
• JVM 级别更改。大多数现代处理器对并发提供某一硬件级别的支持,通常以 compare-and-swap (CAS)指令形式。CAS 是一种低级别的、细粒度的技术,它允许多个线程更新一个内存位置,同时能够检测其他线程的冲突并进行恢复。它是许多高性能并发算法的基础。在 JDK 5.0 之前,Java 语言中用于协调线程之间的访问的惟一原语是同步,同步是更重量级和粗粒度的。 CAS 可以开发高度可伸缩的并发 Java 类。这些更改主要由 JDK 库类使用,而不是由开发人员使用。
• 低级实用程序类 -- 锁定和原子类。使用 CAS 作为并发原语,ReentrantLock 类提供与 synchronized 原语相同的锁定和内存语义,然而这样可以更好地控制锁定(如计时的锁定等待、锁定轮询和可中断的锁定等待)和提供更好的可伸缩性(竞争时的高性能)。大多数开发人员将不再直接使用 ReentrantLock 类,而是使用在 ReentrantLock 类上构建的高级类。
• 高级实用程序类。这些类实现并发构建块,每个计算机科学文本中都会讲述这些类 -- 信号、互斥、闩锁、屏障、交换程序、线程池和线程安全集合类等。大部分开发人员都可以在应用程序中用这些类,来替换许多(如果不是全部)同步、wait() 和 notify() 的使用,从而提高性能、可读性和正确性。
一、Semaphore-计数信号量
从概念上讲,信号量维护了一个许可集。通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。acquire()表示可以从信号量获取一个许可,提供之前线程将会阻塞。release()表示释放许可,并返回给信号量。用法如下:
01 | import java.util.concurrent.ExecutorService; |
02 | import java.util.concurrent.Executors; |
03 | import java.util.concurrent.Semaphore; |
04 | public class MySemaphore extends Thread { |
07 | public MySemaphore( int i,Semaphore s){ |
13 | if (position.availablePermits()> 0 ){ |
14 | System.out.println( "顾客[" + this .id+ "]进入厕所,有空位" ); |
17 | System.out.println( "顾客[" + this .id+ "]进入厕所,没空位,排队" ); |
20 | System.out.println( "顾客[" + this .id+ "]获得坑位" ); |
21 | Thread.sleep(( int )(Math.random()* 1000 )); |
22 | System.out.println( "顾客[" + this .id+ "]使用完毕" ); |
29 | public static void main(String args[]){ |
30 | ExecutorService list=Executors.newCachedThreadPool(); |
31 | Semaphore position= new Semaphore( 2 ); |
32 | for ( int i= 0 ;i< 10 ;i++){ |
33 | list.submit( new MySemaphore(i+ 1 ,position)); |
36 | position.acquireUninterruptibly( 2 ); |
37 | System.out.println( "使用完毕,需要清扫了" ); |
二、CompletionService
将生产新的异步任务与使用已完成任务的结果分离开来的服务。生产者 submit 执行的任务。使用者 take 已完成的任务,并按照完成这些任务的顺序处理它们的结果,即使用 Producer/Consumer 模式,其中生产者创建任务并提交,消费者请求完成任务的结果并处理这些结果。CompletionService 依赖于一个单独的 Executor
来实际执行任务,在这种情况下,CompletionService 只管理一个内部完成队列。ExecutorCompletionService
类提供了此方法的一个实现。用法如下:
01 | import java.util.concurrent.Callable; |
02 | import java.util.concurrent.CompletionService; |
03 | import java.util.concurrent.ExecutorCompletionService; |
04 | import java.util.concurrent.ExecutorService; |
05 | import java.util.concurrent.Executors; |
06 | public class MyCompletionService implements Callable<String> { |
09 | public MyCompletionService( int i){ |
12 | public static void main(String[] args) throws Exception{ |
13 | ExecutorService service=Executors.newCachedThreadPool(); |
14 | CompletionService<String> completion= new ExecutorCompletionService<String>(service); |
15 | for ( int i= 0 ;i< 10 ;i++){ |
16 | completion.submit( new MyCompletionService(i)); |
18 | for ( int i= 0 ;i< 10 ;i++){ |
19 | System.out.println(completion.take().get()); |
23 | public String call() throws Exception { |
24 | Integer time=( int )(Math.random()* 1000 ); |
26 | System.out.println( this .id+ " start" ); |
28 | System.out.println( this .id+ " end" ); |
33 | return this .id+ ":" +time; |
三、CountdownLatch
有两个重要的方法:
await():使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断
countDown():递减锁存器的计数,如果计数到达零,则释放所有等待的线程
下面以模拟运动员比赛说明用法:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchDemo {
private static final int PLAYER_AMOUNT = 5;
public CountDownLatchDemo() {
// TODO Auto-generated constructor stub
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//对于每位运动员,CountDownLatch减1后即结束比赛
CountDownLatch begin = new CountDownLatch(1);
//对于整个比赛,所有运动员结束后才算结束
CountDownLatch end = new CountDownLatch(PLAYER_AMOUNT);
Player[] plays = new Player[PLAYER_AMOUNT];
for(int i=0;i<PLAYER_AMOUNT;i++)
plays[i] = new Player(i+1,begin,end);
//设置特定的线程池,大小为5
ExecutorService exe = Executors.newFixedThreadPool(PLAYER_AMOUNT);
for(Player p:plays)
exe.execute(p); //分配线程
System.out.println("Race begins!");
begin.countDown();
try{
end.await(); //等待end状态变为0,即为比赛结束
}catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}finally{
System.out.println("Race ends!");
}
exe.shutdown();
}
}
public class Player implements Runnable {
private int id;
private CountDownLatch begin;
private CountDownLatch end;
public Player(int i, CountDownLatch begin, CountDownLatch end) {
// TODO Auto-generated constructor stub
super();
this.id = i;
this.begin = begin;
this.end = end;
}
@Override
public void run() {
// TODO Auto-generated method stub
try{
begin.await(); //等待begin的状态为0
Thread.sleep((long)(Math.random()*100)); //随机分配时间,即运动员完成时间
System.out.println("Play"+id+" arrived.");
}catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}finally{
end.countDown(); //使end状态减1,最终减至0
}
}
}
四、CyclicBarrier
允许一组线程互相等待,直到所有子线程都到达了这个屏障时,再一起继续执行后面的动作。
两个重要方法:
await():在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待
getParties():返回要求启动此 barrier 的参与者数目
下面举例来说明用法:
年末公司组织团建,要求每一位员工周六上午8点【自驾车】到公司门口集合,然后【自驾车】前往目的地。 在这个案例中,公司作为主线程,员工作为子线程。
package com.test.spring.support;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author javaloveiphone
* @date 创建时间:2017年1月25日 上午10:59:11
* @Description:
*/
public class Company {
public static void main(String[] args) throws InterruptedException {
int count = 5;
CyclicBarrier barrier = new CyclicBarrier(count+1);
ExecutorService threadPool = Executors.newFixedThreadPool(count);
System.out.println("公司发送通知,每一位员工在周六早上8点【自驾车】到公司大门口集合");
for(int i =0;i<count ;i++){
threadPool.execute(new Employee(barrier,i+1));
Thread.sleep(10);
}
try {
barrier.await();
Thread.sleep(10);
System.out.println("所有员工已经到达公司大门口,公司领导一并【自驾车】同员工前往活动目的地。");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}finally{
threadPool.shutdown();
}
}
}
class Employee implements Runnable{
private CyclicBarrier barrier;
private int employeeIndex;
public Employee(CyclicBarrier barrier,int employeeIndex){
this.barrier = barrier;
this.employeeIndex = employeeIndex;
}
@Override
public void run() {
try {
System.out.println("员工:"+employeeIndex+",正在前往公司大门口集合...");
Thread.sleep(10*employeeIndex);
System.out.println("员工:"+employeeIndex+",已到达。");
barrier.await();
Thread.sleep(10);
System.out.println("员工:"+employeeIndex+",【自驾车】前往目的地");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
公司发送通知,每一位员工在周六早上8点【自驾车】到公司大门口集合
员工:1,正在前往公司大门口集合...
员工:1,已到达。
员工:2,正在前往公司大门口集合...
员工:3,正在前往公司大门口集合...
员工:2,已到达。
员工:4,正在前往公司大门口集合...
员工:5,正在前往公司大门口集合...
员工:3,已到达。
员工:4,已到达。
员工:5,已到达。
员工:3,【自驾车】前往目的地
员工:5,【自驾车】前往目的地
所有员工已经到达公司大门口,公司领导一并【自驾车】同员工前往活动目的地。
员工:4,【自驾车】前往目的地
员工:1,【自驾车】前往目的地
员工:2,【自驾车】前往目的地