信号量(Semaphore),倒计时器(CountDownlatch),屏障(CycliBarrier)

Semaphore

信号量控制一起进入线程的数量,通俗点讲是 synchronized 的加强版,作用是控制线程的并发数量

	
		final Semaphore sh = new Semaphore(2);//信号量为2
		for(int i = 0; i < 3; i++) {
			Thread t=new Thread(new Runnable() {		
				public void run() {					
					try {
						sh.acquire();      //获取信号量
						for(int i = 0; i< 10; i++) {
							System.out.println("执行的线程"+Thread.currentThread().getName()+"循环第"+i+"次");
						}
						Thread.sleep(5000); //一个线程休眠5s				
						sh.release();		//释放信号量
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}				
				}
			});
			t.start();
		}	
	

这三个线程只有两个能同时执行,第三个线程需要在前两线程有一个结束后5s后才能执行,执行的标准是信号量是否为0,

CountDownlatch

一个任务等待一组任务,结束后,被唤醒的功能
注意:直到由于 countDown() 方法的调用而导致当前计数达到零,之后所有等待线程被释放,并且任何后续的await 调用立即返回。 这是一个一次性的现象 - 计数无法重置。 如果您需要重置计数的版本,请考虑使用CyclicBarrier 。 .

(1)首先示例正常多个线程全部完成再执行下面的

final  static CountDownLatch ctl = new CountDownLatch(10);
		
	public static void main(String[] args) throws Exception{
		  ExecutorService exec = Executors.newFixedThreadPool(2);
	
	        for (int i=0; i<10; i++){
				Thread t=new Thread(new Runnable() {		
					public void run() {					
						try {						
							for(int i = 0; i< 10; i++) {
								System.out.println("执行的线程"+Thread.currentThread().getName()+"循环第"+i+"次");
							}
							Thread.sleep(1000);
							ctl.countDown();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}				
					}
				});
				exec.submit(t);
			
	        }
	        // 等待检查
	        ctl.await();
	        
	        // 需要等待的所有线程执行完毕,可以继续往下执行
	        System.out.println("需要等待的所有线程结束");
	        // 关闭线程池
	       exec.shutdown();
	    }	
		 

信号量(Semaphore),倒计时器(CountDownlatch),屏障(CycliBarrier)_第1张图片
(2) 一个倒计时器循环多线程

final  static CountDownLatch ctl = new CountDownLatch(10);
		
	public static void main(String[] args) throws Exception{
		  ExecutorService exec = Executors.newFixedThreadPool(2);
		  for(int j = 0;j<2;j++) {
	        for (int i=0; i<10; i++){
				Thread t=new Thread(new Runnable() {		
					public void run() {					
						try {						
							for(int i = 0; i< 10; i++) {
								System.out.println("执行的线程"+Thread.currentThread().getName()+"循环第"+i+"次");
							}
							Thread.sleep(1000);
							ctl.countDown();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}				
					}
				});
				exec.submit(t);
			
	        }
	        // 等待检查
	        ctl.await();
	        
	        // 需要等待的所有线程执行完毕,可以继续往下执行
	        System.out.println("需要等待的所有线程执行完毕,可以执行下面的程序!");
	       
	    }	
		  // 关闭线程池
	       exec.shutdown();
	}

信号量(Semaphore),倒计时器(CountDownlatch),屏障(CycliBarrier)_第2张图片
出现问题了,第二个多线程没等全部的线程结束就执行了
所以:CountDownLatch 在数值减为0后不重置,一锤子买卖

CycliBarrier

一组线程彼此互相等待


	final  static CyclicBarrier cb = new CyclicBarrier(5);  //屏障线程的数量为5
		
	public static void main(String[] args) throws Exception{
		  ExecutorService exec = Executors.newFixedThreadPool(5);//线程池
	        for (int i=0; i<5; i++){
				Thread t=new Thread(new Runnable() {		
					public void run() {					
						try {													
							System.out.println("执行的线程"+Thread.currentThread().getName()+"到达屏障");
							System.out.println("线程"+Thread.currentThread().getName()+"等待其他线程到达屏障");
							Thread.sleep(1000);
							cb.await();  //到达屏障
							System.out.println(Thread.currentThread().getName()+"冲破屏障");
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}				
					}
				});
				exec.submit(t);		
	        }	      	     	  
		  // 关闭线程池
	       exec.shutdown();
	}

结果
信号量(Semaphore),倒计时器(CountDownlatch),屏障(CycliBarrier)_第3张图片
当然可以重置(可以主动reset(),也可以被动 ),不像CountDownlatch 不能重置

比较CountDownlatch和CycliBarrier

  • CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的
  • CountDownLatch 参与的线程的目的是不一样的,有的在倒计时,有的在等待倒计时结束,CyclicBarrier 参与的线程的目的是一样的

你可能感兴趣的:(并发编程,java)