CyclicBarri和 CountDownLatch的使用场景

来源:互联网 发布:sql视图和表的区别 编辑:程序博客网 时间:2024/05/17 02:02

CyclicBarrier的用法

CyclicBarrier和CountDownLatch一样,都是关于线程的计数器。

用法略有不同,测试代码如下:

复制代码
 1 public class TestCyclicBarrier { 2  3     private static final int THREAD_NUM = 5; 4      5     public static class WorkerThread implements Runnable{ 6  7         CyclicBarrier barrier; 8          9         public WorkerThread(CyclicBarrier b){10             this.barrier = b;11         }12         13         @Override14         public void run() {15             // TODO Auto-generated method stub16             try{17                 System.out.println("Worker's waiting");18                 //线程在这里等待,直到所有线程都到达barrier。19                 barrier.await();20                 System.out.println("ID:"+Thread.currentThread().getId()+" Working");21             }catch(Exception e){22                 e.printStackTrace();23             }24         }25         26     }27     28     /**29      * @param args30      */31     public static void main(String[] args) {32         // TODO Auto-generated method stub33         CyclicBarrier cb = new CyclicBarrier(THREAD_NUM, new Runnable() {34             //当所有线程到达barrier时执行35             @Override36             public void run() {37                 // TODO Auto-generated method stub38                 System.out.println("Inside Barrier");39                 40             }41         });42         43         for(int i=0;i<THREAD_NUM;i++){44             new Thread(new WorkerThread(cb)).start();45         }46     }47 48 }49 /*50 以下是输出:51 Worker's waiting52 Worker's waiting53 Worker's waiting54 Worker's waiting55 Worker's waiting56 Inside Barrier57 ID:12 Working58 ID:8 Working59 ID:11 Working60 ID:9 Working61 ID:10 Working62 */
复制代码
  1.  CyclicBarrier初始化时规定一个数目,然后计算调用了CyclicBarrier.await()进入等待的线程数。当线程数达到了这个数目时,所有进入等待状态的线程被唤醒并继续。 
  2.  CyclicBarrier就象它名字的意思一样,可看成是个障碍, 所有的线程必须到齐后才能一起通过这个障碍。 
  3.  CyclicBarrier初始时还可带一个Runnable的参数, 此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。

CountDownLatch的用法


让我们尝试罗列出在java实时系统中CountDownLatch都有哪些使用场景。我所罗列的都是我所能想到的。如果你有别的可能的使用方法,请在留言里列出来,这样会帮助到大家。

  1. 实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。
  2. 开始执行前等待n个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。
  3. 死锁检测:一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。

CountDownLatch使用例子

在这个例子中,我模拟了一个应用程序启动类,它开始时启动了n个线程类,这些线程将检查外部系统并通知闭锁,并且启动类一直在闭锁上等待着。一旦验证和检查了所有外部服务,那么启动类恢复执行。

BaseHealthChecker.java:这个类是一个Runnable,负责所有特定的外部服务健康的检测。它删除了重复的代码和闭锁的中心控制代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public abstract class BaseHealthChecker implements Runnable {
 
    privateCountDownLatch _latch;
    privateString _serviceName;
    privateboolean_serviceUp;
 
    //Get latch object in constructor so that after completing the task, thread can countDown() the latch
    publicBaseHealthChecker(String serviceName, CountDownLatch latch)
    {
        super();
        this._latch = latch;
        this._serviceName = serviceName;
        this._serviceUp =false;
    }
 
    @Override
    publicvoidrun() {
        try{
            verifyService();
            _serviceUp =true;
        }catch(Throwable t) {
            t.printStackTrace(System.err);
            _serviceUp =false;
        }finally{
            if(_latch !=null) {
                _latch.countDown();
            }
        }
    }
 
    publicString getServiceName() {
        return_serviceName;
    }
 
    publicbooleanisServiceUp() {
        return_serviceUp;
    }
    //This methos needs to be implemented by all specific service checker
    publicabstractvoidverifyService();
}

NetworkHealthChecker.java:这个类继承了BaseHealthChecker,实现了verifyService()方法。DatabaseHealthChecker.javaCacheHealthChecker.java除了服务名和休眠时间外,与NetworkHealthChecker.java是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class NetworkHealthChecker extendsBaseHealthChecker
{
    publicNetworkHealthChecker (CountDownLatch latch)  {
        super("Network Service", latch);
    }
 
    @Override
    publicvoidverifyService()
    {
        System.out.println("Checking "+this.getServiceName());
        try
        {
            Thread.sleep(7000);
        }
        catch(InterruptedException e)
        {
            e.printStackTrace();
        }
        System.out.println(this.getServiceName() +" is UP");
    }
}

ApplicationStartupUtil.java:这个类是一个主启动类,它负责初始化闭锁,然后等待,直到所有服务都被检测完。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class ApplicationStartupUtil
{
    //List of service checkers
    privatestaticList<BaseHealthChecker> _services;
 
    //This latch will be used to wait on
    privatestaticCountDownLatch _latch;
 
    privateApplicationStartupUtil()
    {
    }
 
    privatefinalstatic ApplicationStartupUtil INSTANCE =new ApplicationStartupUtil();
 
    publicstaticApplicationStartupUtil getInstance()
    {
        returnINSTANCE;
    }
 
    publicstaticbooleancheckExternalServices()throwsException
    {
        //Initialize the latch with number of service checkers
        _latch =newCountDownLatch(3);
 
        //All add checker in lists
        _services =newArrayList<BaseHealthChecker>();
        _services.add(newNetworkHealthChecker(_latch));
        _services.add(newCacheHealthChecker(_latch));
        _services.add(newDatabaseHealthChecker(_latch));
 
        //Start service checkers using executor framework
        Executor executor = Executors.newFixedThreadPool(_services.size());
 
        for(finalBaseHealthChecker v : _services)
        {
            executor.execute(v);
        }
 
        //Now wait till all services are checked
        _latch.await();
 
        //Services are file and now proceed startup
        for(finalBaseHealthChecker v : _services)
        {
            if( ! v.isServiceUp())
            {
                returnfalse;
            }
        }
        returntrue;
    }
}

现在你可以写测试代码去检测一下闭锁的功能了。

1
2
3
4
5
6
7
8
9
10
11
12
public class Main {
    publicstaticvoid main(String[] args)
    {
        booleanresult =false;
        try{
            result = ApplicationStartupUtil.checkExternalServices();
        }catch(Exception e) {
            e.printStackTrace();
        }
        System.out.println("External services validation completed !! Result was :: "+ result);
    }
}
1
2
3
4
5
6
7
8
9
Output inconsole:
 
Checking Network Service
Checking Cache Service
Checking Database Service
Database Service is UP
Cache Service is UP
Network Service is UP
External services validation completed !! Result was ::true

常见面试题

可以为你的下次面试准备以下一些CountDownLatch相关的问题:

  • 解释一下CountDownLatch概念?
  • CountDownLatch 和CyclicBarrier的不同之处?
  • 给出一些CountDownLatch使用的例子?
  •  CountDownLatch 类中主要的方法?
原创粉丝点击