jdk的CountdownLatch和CyclicBarrier的使用

JDK的current包下提供了一系列的多线程相关的工具类,很多类都是出自Doug Lea之手, 正是这些大神的无私奉献才有了java能够在20年的时间里不断的成熟,不断的发展,才有了当今丰富多彩的java体系的开源世界。

其中的CountDownLatch和CyclicBarrier是在JDK5之后加入的,提供了一些线程之间协作的手段。在没有这些类之前,要完成线程之间的协作只有通过join方法,比较容易出错,编写多线程的代码是件比较痛苦的事情。有了这些多线程的工具类后,多线程的协助容易了太多。

项目中有遇到一个场景,之前串行化的动作,由于各个串行化动作之间没有太多的关联,而如果一个一个的进行操作,则耗时会比较多,对用户造成的延时就比较长,为了解决这个问题,项目上进行了分析后决定将串行化的动作改为多线程并行操作来实现,从而提供系统的响应速度,这样就涉及到线程之间的协助。

使用CountDownLatch就非常适合

首先在主线程中创建一个CountDownLatch然后在各个任务线程中在完成了相关的操作后,将latch减1,当所有的任务都已经完成了之后主线程会从await中醒过来。如下所示


                final CountDownLatch cdl = new CountDownLatch(3);
		final Map<String, Object> result = new HashMap<String, Object>();
		ExecutorService exec = Executors.newCachedThreadPool();
		exec.submit(new Runnable() 
		{
			@Override
			public void run()
			{
				// TODO Auto-generated method stub
				// TODO Auto-generated method stub
				try {
					Thread.currentThread().sleep(3000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				result.put("TASK1", "Task1Result");
				System.out.println("Task1 End");
				cdl.countDown();
			}
		
		});

		exec.submit(new Runnable() 
		{
			@Override
			public void run()
			{
				// TODO Auto-generated method stub
				// TODO Auto-generated method stub
				try {
					Thread.currentThread().sleep(2000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				result.put("TASK2", "Task2Result");
				System.out.println("Task2 End");
				cdl.countDown();
			}	
		});
	
		exec.submit(new Runnable() 
		{
			@Override
			public void run()
			{
				// TODO Auto-generated method stub
				try {
					Thread.currentThread().sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				result.put("TASK3", "Task3Result");
				
				System.out.println("Task3 End");
				cdl.countDown();
			}		
		});
		
		System.out.println("MainThread Will Wait");
		cdl.await(10, TimeUnit.SECONDS);
		System.out.println("All Task End Start next process");
		StringBuilder resultStr = new StringBuilder();
		//结束了之后,读取result的数据 继续后续的动作
		for (Entry<String, Object> entry : result.entrySet())
		{
			resultStr.append(entry.getValue());
		}
		System.out.println(resultStr);
 
结果如下
MainThread Will Wait
Task3 End
Task2 End
Task1 End
All Task End Start next process
Task1ResultTask2ResultTask3Result

这样可以将串行化的动作修改为并行化的动作。。

2. CyclicBarrier的使用

CyclicBarrier的使用和CountDownLatch相反,CyclicBarrier主要是作为一个统一的起始点,当每个线程都准备好了之后,才开始统一的动作,如要进行赛跑比赛,需要每个人都准备好了之后才可以开始,这样就需要一个协调者来对各个线程进行协调,如下所示

final CyclicBarrier cb = new CyclicBarrier(3, new Runnable(){

			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.out.println("All waiting is finished");
			}
			
		});
		
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < 3; i++)
		{
			exec.execute(new Runnable(){

				@Override
				public void run() 
				{
					// TODO Auto-generated method stub
					System.out.println(Thread.currentThread().getName() 
							+ "Waitting Number" +  cb.getNumberWaiting());
					try 
					{
						System.out.println(Thread.currentThread().getName() + " Begin Preparing");
						Thread.sleep(new Random().nextInt(3000));
						cb.await(10, TimeUnit.SECONDS);
						System.out.println(Thread.currentThread().getName() + "Start Running ");
					}
					catch (Exception e) 
					{
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + " End Running");					
				}				
			});
			
		}
		
		System.out.println("Main Thread Wait");
		exec.shutdown();
运行结果如下
pool-1-thread-1Waitting Number0pool-1-thread-2Waitting Number0Main Thread Waitpool-1-thread-3Waitting Number0pool-1-thread-3 Begin Preparingpool-1-thread-2 Begin Preparingpool-1-thread-1 Begin PreparingAll waiting is finishedpool-1-thread-3Start Running pool-1-thread-3 End Runningpool-1-thread-1Start Running pool-1-thread-1 End Runningpool-1-thread-2Start Running pool-1-thread-2 End Running


这样所有的线程就会有一个初始的起始点开始运行。对于解决特定场景的问题还是比较有用的,,

个人感觉CountDownLatch在编码中使用到的机会更多。。


















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值