java 中间件学习4-CountDownLatch、CyclicBarrier、Future和FutureTask

来源:互联网 发布:mac可以玩什么国内网游 编辑:程序博客网 时间:2024/05/16 06:38

1、CountDownLatch

CountDownLatch主要提供的机制是多个线程都达到了预期状态或完成预期工作时触发事件,其他线程可以等待这个事件来触发自己后续的工作,这里等待线程是可以多个。

例如:
    package com.jd.learn.test;    import java.text.SimpleDateFormat;    import java.util.Date;    import java.util.concurrent.CountDownLatch;    public class CountDownLatchTest {        final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");          public static void main(String[] args) throws InterruptedException {              CountDownLatch latch=new CountDownLatch(2);//两个工人的协作              Worker worker1=new Worker("zhang san", 7000, latch);              Worker worker2=new Worker("li si", 8000, latch);            Boss boss1 = new Boss("Boss1", latch);            Boss boss2 = new Boss("Boss2", latch);            worker1.start();//              worker2.start();//              boss1.start();            boss2.start();            latch.await();//等待所有工人完成工作              System.out.println("all work done at "+sdf.format(new Date()));          }          static class Worker extends Thread{              String workerName;               int workTime;              CountDownLatch latch;              public Worker(String workerName ,int workTime ,CountDownLatch latch){                   this.workerName=workerName;                   this.workTime=workTime;                   this.latch=latch;              }              public void run(){                  System.out.println("Worker "+workerName+" do work begin at "+sdf.format(new Date()));                  doWork();//工作了                  System.out.println("Worker "+workerName+" do work complete at "+sdf.format(new Date()));                  latch.countDown();//工人完成工作,计数器减一              }              private void doWork(){                  try {                      Thread.sleep(workTime);                  } catch (InterruptedException e) {                      e.printStackTrace();                  }              }          }         static class Boss extends Thread{              String bossName;               CountDownLatch latch;              public Boss(String bossName ,CountDownLatch latch){                   this.bossName=bossName;                   this.latch=latch;              }              public void run(){                try {                    latch.await();                    System.out.println("Boss "+bossName+" is waiting  "+sdf.format(new Date()));                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }          }}

上面例子中,工人一直在工作,老板需要等到工人们都完成才做后续的事,如果有多个老板在等待,这就是CountDownLatch的主要功能与作用;

2、CyclicBarrier

这个单词从字面上理解是指循环屏障。CyclicBarrier可以协同多个线程,让多个线程在这个屏幕前等待,直到所有线程都达到屏障,再一起执行后面的动作。    **CountDownLatch与CyclicBarrier之间的一个大的区别是,CountDownLatch是在多个线程都进行了latch.countDown后才触发事件,唤醒线程,然后执行后续线程。CyclicBarrier是一个栅栏,用于同步所有调用awaite方法的线程。**

CountDownLatch是不能循环使用,CyclicBarrier可以循环使用。就是CyclicBarrier可以多次被初始化。
实例代码:

package com.jd.learn.test;import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;public class CyclicBarrierDemo {    private static int[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };    final static SimpleDateFormat sdf = new SimpleDateFormat(            "yyyy-MM-dd HH:mm:ss");    public static void main(String[] args) throws InterruptedException,            BrokenBarrierException {        CyclicBarrier latch = new CyclicBarrier(2 + 1);// 两个工人的协作        System.out.println("all work start at " + sdf.format(new Date()));        for (int i = 0; i < 10; i++) {            Worker worker1 = new Worker(data[i], i * 1000 + 1, latch);            worker1.start();        }        int i = 0;        while (i < 5) {            latch.await();            System.out.println("all work done at " + sdf.format(new Date()));            latch.reset();            i++;        }        System.out.println("all thread is Done");    }    static class Worker extends Thread {        int data;        int workTime;        CyclicBarrier cyclicBarrier;        public Worker(int data, int workTime, CyclicBarrier cyclicBarrier) {            this.data = data;            this.workTime = workTime;            this.cyclicBarrier = cyclicBarrier;        }        public void run() {            try {                System.out.println("this number is " + data);                doWork();// 工作了                cyclicBarrier.await();            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            } catch (BrokenBarrierException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }// 工人完成工作,计数器减一        }        private void doWork() {            try {                Thread.sleep(workTime);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

输出结果:

all work start at 2015-06-09 19:47:14this number is 1this number is 2this number is 5this number is 7this number is 8this number is 6this number is 10this number is 9this number is 3this number is 4all work done at 2015-06-09 19:47:15all work done at 2015-06-09 19:47:17all work done at 2015-06-09 19:47:19all work done at 2015-06-09 19:47:21all work done at 2015-06-09 19:47:23all thread is Done

另外:CyclicBarrier初始时还可带一个Runnable的参数, 此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。

3、Future和FutureTask

Future是一个接口,FutureTask是一个具体实现类。FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。

public interface Future Future 表示异步计算的结果。
Future有个get方法而获取结果只有在计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常。

FutureTask是为了弥补Thread的不足而设计的,它可以让程序员准确地知道线程什么时候执行完成并获得到线程执行完成后返回的结果(如果有需要)。

FutureTask是一种可以取消的异步的计算任务。它的计算是通过Callable实现的,它等价于可以携带结果的Runnable,并且有三个状态:等待、运行和完成。完成包括所有计算以任意的方式结束,包括正常结束、取消和异常。

实例代码:

package com.jd.learn.test;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;public class FutureDemo {    public static void main(String[] args) throws InterruptedException, ExecutionException{//      Callable<String> myCallable = new MyCallable("test");//      FutureTask<String> future = new FutureTask<String>(myCallable);        FutureTask<String> future = new FutureTask<String>(new myRunnable(),null);        new Thread(future).start();        while(!future.isDone()){            System.out.println("future get data is not Done!!");            Thread.sleep(2000);        }        System.out.println("future get data is Done!!,return data is "+future.get());    }    public static class myRunnable implements Runnable{//      private String myName;//      public myRunnable(String name){//          this.myName = name;//      }        @Override        public void run() {            // TODO Auto-generated method stub            try {                Thread.sleep(10000);                System.out.println("this is myRunnable out !! ");            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        //  return "this is MyCallable return "+myName;        }    }    public static class MyCallable implements Callable<String>{        private String myName;        public MyCallable(String name){            this.myName = name;        }        @Override        public String call() throws Exception {            // TODO Auto-generated method stub            Thread.sleep(10000);            return "this is MyCallable return "+myName;        }    }}

我们可以看到,Future是可以支持callable与runable的

构造方法摘要
FutureTask(Callable callable)
创建一个 FutureTask,一旦运行就执行给定的 Callable。 Callable执行指定的call来获取对应的结果。

FutureTask(Runnable runnable, V result)
创建一个 FutureTask,一旦运行就执行给定的 Runnable,并安排成功完成时 get 返回给定的结果 。

所以,如果是使用 callable获取的输出结果为:

future get data is not Done!!future get data is not Done!!future get data is not Done!!future get data is not Done!!future get data is not Done!!future get data is not Done!!future get data is Done!!,return data is this is MyCallable return test

如果是使用runable获得的输出结果为:

future get data is not Done!!future get data is not Done!!future get data is not Done!!future get data is not Done!!future get data is not Done!!future get data is not Done!!this is myRunnable out !! future get data is Done!!,return data is null

为什么会使用Runnable,它不具有返回数据的功效,可能在我们平常使用中,会使用到它等价于可以携带结果的Runnable,并且有三个状态:等待、运行和完成状态。Runnable是本身不带有状态的。

0 0