CountDownLatch和CyclicBarrier和Semaphore应用

全文概要

本文将介绍并发库中三个线程辅助类,CountDownLatchCyclicBarrierSemaphore。本文主要内容如下:

  1. 通过一个案例介绍CountDownLatch的用法和使用场景;
  2. 通过一个案例介绍CyclicBarrier的用法和使用场景;
  3. 通过一个案例介绍Semaphore的用法和使用场景。

CountDownLatch

  • CountDownLatch简介

CountDownLatch的有一个计数器,每隔线程执行都会将这个计数器减1,当计数器为0时,当前线程才能继续执行;

  • 代码案例
package com.tml.javaCore.concurrent;

import java.util.concurrent.CountDownLatch;
/**
 * <p>介绍concurrent包中一个多线程辅助类CountDownLatch的使用
 * @author Administrator
 *
 */
public class CountDownLatchDemo {
	private static final int SIZE = 5;
	private  static CountDownLatch countDownLatch = new CountDownLatch(SIZE);
	
	public static void main(String[] args) {
		CountDownLatchDemo demo = new CountDownLatchDemo();
		try {
			for(int i=0;i<SIZE;i++){
				//新建5个线程
				new Thread(new Runnable() {
					public void run() {
						demo.work();
					}
				}, "thread_0" + (i+1)).start();
			}
			//主线程等待,当五个线程的任务执行完成后,才继续执行主线程后续的逻辑
			countDownLatch.await();
			System.out.println(Thread.currentThread().getName() + " end!");
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}
	
	private void work(){
		try {
			System.out.println(Thread.currentThread().getName() + " ready to sleep 1s");
			Thread.sleep(1000);
			//将countDownLatch的数值减一
			countDownLatch.countDown();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}
  • 结果输出
thread_01 ready to sleep 1s
thread_02 ready to sleep 1s
thread_04 ready to sleep 1s
thread_03 ready to sleep 1s
thread_05 ready to sleep 1s

main end!

  • 结果分析
  1. 新建了一个CountDownLatch对象,它的计数器是5,主线程中创建了五个线程;
  2. 调用线程的start()方法启动线程后,主线程执行countDownLatch.await(),表示主线程必须等待countDownLatch对象的计数器置为0,才能继续秩序执行;
  3. 五个线程分别执行work()方法,调用countDownLatch.countDown()的作用是将计数器减1;
  4. 当五个线程全部执行完毕后,即countDownLatch的计数器为0,此时唤醒主线程,主线程继续执行后续逻辑。

CyclicBarrier

  • CyclicBarrier简介

CyclicBarrier对象创建的时候,需要定义一个参与者数量,调用该对象的await()方法,会将参与者数量加1,同时线程进入阻塞状态。只有当CyclicBarrier对象的参与者数量和定义的参与者数量一致时,才会重新唤醒被阻塞的线程,让其继续执行后续逻辑。

  • 代码案例
package com.tml.javaCore.concurrent;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
 * <p>介绍concurrent包中一个多线程辅助类CyclicBarrier的使用
 * @author Administrator
 *
 */
public class CyclicBarrierDemo {
	private static final int SIZE = 5;
	//新建一个barrier1对象,它将在给定数量的线程处于等待状态下执行
	private static CyclicBarrier barrier1 = new CyclicBarrier(SIZE);
	//新建一个barrier1对象,它将在给定数量的线程处于等待状态下执行,同时执行runnable里面的任务
		private static CyclicBarrier barrier2 = new CyclicBarrier(SIZE,new Runnable() {
			public void run() {
				System.out.println(Thread.currentThread().getName() + " barrier to go!");
			}
		});
	public static void main(String[] args) {
		CyclicBarrierDemo demo =  new CyclicBarrierDemo();
		System.out.println(Thread.currentThread().getName() + " start!");
		for(int i=1;i<=SIZE;i++){
			new Thread(new Runnable() {
				public void run() {
					demo.work();
				}
			},"thread_0" + i).start();
		}
		System.out.println(Thread.currentThread().getName() + " end!");
	}
	
	
	private void work(){
			System.out.println(Thread.currentThread().getName() + " is waiting for barrier!");
			try {
				
				System.out.println(Thread.currentThread().getName() + 
						" is working !");
				Thread.sleep(1000);
				//将barrier的参与者加1
				barrier1.await();
				//当barrier的参与者达到SIZE的时候,执行后续逻辑
				System.out.println(Thread.currentThread().getName() + "continue....");
			} catch (BrokenBarrierException e) {
				e.printStackTrace();
			}catch (InterruptedException e) {
				e.printStackTrace();
			}
		
	}
}
  • 结果输出

使用barrier1对象的输出:

main start!
thread_01 is waiting for barrier!
thread_01 is working !
thread_03 is waiting for barrier!
main end!
thread_02 is waiting for barrier!
thread_03 is working !
thread_02 is working !
thread_04 is waiting for barrier!
thread_04 is working !
thread_05 is waiting for barrier!
thread_05 is working !
thread_05continue....
thread_02continue....
thread_03continue....
thread_04continue....

thread_01continue....

使用barrier2对象的输出:

main start!
thread_01 is waiting for barrier!
main end!
thread_03 is waiting for barrier!
thread_03 is working !
thread_02 is waiting for barrier!
thread_02 is working !
thread_01 is working !
thread_04 is waiting for barrier!
thread_05 is waiting for barrier!
thread_04 is working !
thread_05 is working !
thread_05 barrier to go!
thread_05continue....
thread_03continue....
thread_01continue....
thread_04continue....

thread_02continue....

  • 结果分析
  1. 闯进CyclicBarrier对象的时候,有两个构造方法。barrier1对象表示有5个参与者,当参与者的数量达到5时执行;barrier1对象表示有5个参与者,当参与者的数量达到5时,先执行runnable里面的任务,接着执行线程后续逻辑;
  2. 主线程中用循环创建了5个线程,启动线程,主线程执行完毕;
  3. 5个线程分别执行work()方法,执行await()方法时,将参与者数量加1,同时该线程进入阻塞,只有当barrier对象的参与者数量达到5时,才会唤醒该线程;
  4. 唤醒线程的时候,若采用barrier1对象则直接执行线程后续逻辑,若barrier2则先会执行runnable()里面的任务再执行线程里面的后续代码。

Semaphore

  • Semaphore简介

Semaphore的作用是在相同的时刻,最多能允许指定数量的线程执行,若并发的线程数量大于指定的线程数,则多余的线程必须等待,直到有线程任务执行完毕后,该线程才有机会执行。

  • 代码案例
package com.tml.javaCore.concurrent;

import java.util.concurrent.Semaphore;

/**
 * <p>介绍concurrent包中一个多线程辅助类Semaphore的使用
 * @author Administrator
 *
 */
public class SemaphoreDemo {
	//新建一个容量为2的信号量,意义是同时只能允许两个线程并发
	private static Semaphore semaphore =new Semaphore(2);
	public static void main(String[] args) {
		SemaphoreDemo demo = new SemaphoreDemo();
		//创建3个线程,小于semaphore的信号量,所以,同时只能有两个线程执行,只有等其中一个线程执行完毕了,第三个线程才能执行
		for(int i=1;i<=3;i++){
			new Thread(new Runnable() {
				public void run() {
					demo.work();
				}
			}, "thread_0" + i).start();
		}
		
		
	}
	
	private void work(){
		try {
			//在semaphore申请一个信号量
			semaphore.acquire();
			System.out.println(Thread.currentThread().getName() + " ready to work!");
			Thread.sleep(2000);
			System.out.println(Thread.currentThread().getName() + " end to work!");
			//释放掉刚刚申请的semaphore信号量
			semaphore.release();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}

}
  • 结果输出
thread_01 ready to work!
thread_02 ready to work!
thread_01 end to work!
thread_02 end to work!
thread_03 ready to work!

thread_03 end to work!

  • 结果分析
  1. 创建一个容量为2的信号量对象semaphore,意义是同时只能允许两个线程并发;
  2. 主线程中创建了三个线程,启动线程,主线程执行完毕;
  3. 三个线程分别执行work()方法,执行work方法时先调用semaphore.acquire(),意义是在semaphore申请一个信号量,执行work方法结束前调用semaphore.release(),意义是释放掉刚刚申请的semaphore信号量;
  4. 结果是只能两个线程并发执行,第三个线程只能等待其中一个线程执行完毕后,才能执行。

猜你喜欢

转载自blog.csdn.net/tianmlin1/article/details/79398265
今日推荐