concurrent包

来源:互联网 发布:怎样退货给淘宝卖家 编辑:程序博客网 时间:2024/05/18 07:15

 参考博文: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()表示释放许可,并返回给信号量。用法如下:

01import java.util.concurrent.ExecutorService;
02import java.util.concurrent.Executors;
03import java.util.concurrent.Semaphore;
04public class MySemaphoreextends Thread {
05Semaphore position;
06private int id;
07public MySemaphore(int i,Semaphore s){
08    this.id=i;
09    this.position=s;
10}
11public void run(){
12    try{
13     if(position.availablePermits()>0){
14      System.out.println("顾客["+this.id+"]进入厕所,有空位");
15     }
16     else{
17      System.out.println("顾客["+this.id+"]进入厕所,没空位,排队");
18     }
19     position.acquire();
20     System.out.println("顾客["+this.id+"]获得坑位");
21     Thread.sleep((int)(Math.random()*1000));
22     System.out.println("顾客["+this.id+"]使用完毕");
23     position.release();
24    }
25    catch(Exception e){
26     e.printStackTrace();
27    }
28}
29public 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));
34    }
35    list.shutdown();
36    position.acquireUninterruptibly(2);
37    System.out.println("使用完毕,需要清扫了");
38    position.release(2);
39}
40}

二、CompletionService

将生产新的异步任务与使用已完成任务的结果分离开来的服务。生产者 submit 执行的任务。使用者take 已完成的任务,并按照完成这些任务的顺序处理它们的结果,即使用 Producer/Consumer 模式,其中生产者创建任务并提交,消费者请求完成任务的结果并处理这些结果。CompletionService 依赖于一个单独的Executor 来实际执行任务,在这种情况下,CompletionService 只管理一个内部完成队列。ExecutorCompletionService 类提供了此方法的一个实现。用法如下:

01import java.util.concurrent.Callable;
02import java.util.concurrent.CompletionService;
03import java.util.concurrent.ExecutorCompletionService;
04import java.util.concurrent.ExecutorService;
05import java.util.concurrent.Executors;
06public class MyCompletionServiceimplements Callable<String> {
07private int id;
08 
09public MyCompletionService(int i){
10   this.id=i;
11}
12public 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));
17   }
18   for(int i=0;i<10;i++){
19    System.out.println(completion.take().get());
20   }
21   service.shutdown();
22}
23public String call() throws Exception {
24   Integer time=(int)(Math.random()*1000);
25   try{
26    System.out.println(this.id+" start");
27    Thread.sleep(time);
28    System.out.println(this.id+" end");
29   }
30   catch(Exception e){
31    e.printStackTrace();
32   }
33   return this.id+":"+time;
34}
35}

三、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);        //创建线程池,可以通过以下方式创建        //ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1,1,60,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(count));        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);            // 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。            //latch.await(long timeout, TimeUnit unit)            System.out.println("所有员工已经到达公司大门口,公司领导一并【自驾车】同员工前往活动目的地。");        } catch (InterruptedException e) {            e.printStackTrace();        } catch (BrokenBarrierException e) {            e.printStackTrace();        }finally{            //最后关闭线程池,但执行以前提交的任务,不接受新任务            threadPool.shutdown();            //关闭线程池,停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。            //threadPool.shutdownNow();        }    }}//分布式工作线程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,【自驾车】前往目的地


原创粉丝点击