CyclicBarrier源码分析

基于jdk1.8源码进行分析的。

继承结构

public class CyclicBarrier

构造方法

CyclicBarrier(int parties)

    public CyclicBarrier(int parties) {
        this(parties, null);
    }

通过源码我们看到是通过调用另外一个构造方法实现的。

CyclicBarrier(int parties, Runnable barrierAction) 

    public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }

内部类

Generation

    private static class Generation {
        //用来表示当前的屏障是否被打破了
        boolean broken = false;
    }

每个CyclicBarrier实例中也有一个Generation域。

成员属性

    /** The lock for guarding barrier entry */
    //所有方法都通过这个锁来同步
    //之所以不使用内置锁主要是因为需要抛出异常
    //此外这里需要的实际上是共享锁,而内置锁不能实现共享锁
    private final ReentrantLock lock = new ReentrantLock();
    /** Condition to wait on until tripped */
    //通过lock得到的一个状态变量
    private final Condition trip = lock.newCondition();
    /** The number of parties */
    //通过构造器传入的参数,表示总的等待线程的数量
    private final int parties;
    /* The command to run when tripped */
    当屏障正常打开后运行的程序,通过最后一个调用await的线程来执行
    private final Runnable barrierCommand;
    /** The current generation */
    //当前的Generation。
    //每当屏障失效或者开闸之后都会自动替换掉。从而实现重置的功能。
    private Generation generation = new Generation();

核心方法

await()

调用await()的线程会等待直到有足够数量的线程调用await——也就是开闸状态。

当最后一个线程到达,或者

  • 有其他线程中断当前线程。则抛出interruptException
  • 指定了限时操作,并到达线程,则抛出TimeoutException
  • 如果barrier被重置,或者屏障处于打破状态,则抛出BrokenBarrierException
    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }

通过源码我们看到是通过dowait实现的。再看主方法源码实现之前,我们先看一下以下两个方法,有助于后面的理解。

nextGeneration()

    private void nextGeneration() {
        // signal completion of last generation
        //唤醒所有等待的线程
        trip.signalAll();
        // set up next generation
        //更新当前线程数量,构造方法传入的,相当于重置剩余线程数量
        count = parties;
        //创建新的Generation,相当于状态重置
        generation = new Generation();
    }

breakBarrier() 

    private void breakBarrier() {
        //改变当前generation的状态,相当于屏障打破状态
        generation.broken = true;
        //记录更新线程数量,相当于重置数量
        count = parties;
        //唤醒所有线程
        trip.signalAll();
    }

上面两个方法比较简单,此处不再一一额外解释。下面我们看主方法源码。

 dowait(boolean timed, long nanos)

    private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        //记录当前lock锁
        final ReentrantLock lock = this.lock;
        //上锁
        lock.lock();
        try {
            //记录当前的屏障的状态
            //后者是成员属性,private Generation generation = new Generation();
            final Generation g = generation;
            //如果成立,说明屏障被打破,抛出异常
            if (g.broken)
                throw new BrokenBarrierException();
            //线程中断,抛出异常
            if (Thread.interrupted()) {
                //如果当前线程被中断,则使得当前generation处于打破状态,重置剩余count。
                //并且唤醒状态变量。这时候其他线程会传播BrokenBarrierException.
                breakBarrier();//这里前面已经粘贴
                //抛出异常
                throw new InterruptedException();
            }
            //进入这里,说明状态没有被打破,且没有发生中断等异常情况
            //线程数量-1操作
            int index = --count;
            //这里也就是要开闸操作
            if (index == 0) {  //如果开闸了,正常运行直接返回0就退出了
                //状态值
                boolean ranAction = false;
                try {
                    //当开闸了,记录运行变量
                    final Runnable command = barrierCommand;
                    //有相应的线程
                    if (command != null)
                        command.run();//当前线程调用command的run方法
                    ranAction = true;//修改状态值
                    //唤醒所有线程
                    nextGeneration();//创建新的Generation,相当于重置状态
                    //返回0
                    return 0;
                } finally {
                    //没有启动成功
                    if (!ranAction)   
                        //打破状态
                        breakBarrier();
                }
            }

            // loop until tripped, broken, interrupted, or timed out
            //死循环
            //执行到这里,说明屏障没有被打破,线程没有被中断,且没有意外,最后一个线程还没有到达
            for (;;) {
                try {
                    //如果没有设置等待时间,则一直等待,直到其它线程唤醒
                    if (!timed)
                        //进入等待
                        trip.await();
                    //如果设置了等待时间,则等待指定的时间。调用对应的condition方法
                    else if (nanos > 0L)
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                    //打破状态抛出异常
                    //如果当前线程被中断了,则使得屏障被打破。并抛出异常。
                    //也是是说,如果再等待的期间发生了中断异常,如果其它线程还没有开始唤醒工作
                    //则当前线程就开始唤醒
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
                        // We're about to finish waiting even if we had not
                        // been interrupted, so this interrupt is deemed to
                        // "belong" to subsequent execution.
                        //翻译内容如下:
                        /*即使我们没有被打断,我们即将完成等待,
                         *因此这个中断被认为“属于”后续执行
                         */
                        //这种捕获了InterruptException之后调用
                        //Thread.currentThread().interrupt()是一种通用的方式。
                        //其实就是为了保存中断状态,从而让其他更高层次的代码注意到这个中断。
                        //但是需要注意的是这里需要其他代码予以配合才行
                        //否则这样做其实是比较危险的一种方式。
                        Thread.currentThread().interrupt();
                    }
                }
                //从阻塞恢复之后,需要重新判断当前的状态---抛出异常
                if (g.broken)
                    throw new BrokenBarrierException();

                if (g != generation)
                    return index;

                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            //释放锁
            lock.unlock();
        }
    }

源码中注释内容我觉得还是比较清晰的,下面我们继续看reset方法的实现。

reset()

    public void reset() {
        //记录当前锁
        final ReentrantLock lock = this.lock;
        //上锁
        lock.lock();
        try {
            //打破屏障,重置数量
            breakBarrier();   // break the current generation
            //创建新的generation,重置数量
            nextGeneration(); // start a new generation
        } finally {
            //释放锁
            lock.unlock();
        }
    }

通过源码分析来看reset方法实现起来,确实比较简单。以上就是整个核心方法的实现过程的源码分析。

package demo;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeoutException;

/**
 * CyclicBarrier测试例程 
 * @ClassName:   CyclicBarrierDemo  
 * @Description: TODO
 * @author       BurgessLee
 * @date         2019年4月30日  
 *
 */
public class CyclicBarrierDemo {
	public static Integer NUM = 3;

	public static void main(String[] args) {
		
//		CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM);
		
		//如果出现异常情况,那么只会影响当前的创建时的command,不会影响其他线程
//		CyclicBarrier cyclicBarrier = new CyclicBarrier(1, new Runnable() {
//		
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start..");
//					int i = 1/0;
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//				System.out.println("============================");
//			}
//		});
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...----");
//					cyclicBarrier.await();
//					System.out.println(Thread.currentThread().getName() +"-end...----");
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread0").start();
		
		//在打破屏障之前,就算是await时间过程,那么最后处理的command也不会抛出异常
//		CyclicBarrier cyclicBarrier = new CyclicBarrier(1, new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start..");
//					TimeUnit.MICROSECONDS.sleep(20);
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//				System.out.println("我会正常等待,不会抛出异常");
//			}
//		});
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...----");
//					cyclicBarrier.await(10,TimeUnit.SECONDS);
//					System.out.println(Thread.currentThread().getName() +"-end...----");
//				} catch (InterruptedException e) {
//					// TODO Auto-generated catch block
//					e.printStackTrace();
//				} catch (BrokenBarrierException e) {
//					// TODO Auto-generated catch block
//					e.printStackTrace();
//				} catch (TimeoutException e) {
//					// TODO Auto-generated catch block
//					e.printStackTrace();
//				}
//			}
//		},"Thread0").start();
		
		//当所有线程都到达barrier之后,然后调用CyclicBarrier自带的Runnable里面的run方法
//		CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM,new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...----");
//					Thread.sleep(2000);
//					System.out.println(Thread.currentThread().getName() +"-end...----");
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				}
//				System.out.println("我最后执行,我是来收尾工作的");
//			}
//		});
//		new Thread(new Runnable() {
//		
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await();
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread0").start();
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await();
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread1").start();
//		
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await();
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread2").start();
		
		//没有打破屏障,那么等待时间到了,会抛出异常
//		CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM);
//		new Thread(new Runnable() {
//		
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await(2, TimeUnit.SECONDS);
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread0").start();
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await();
//					Thread.sleep(100);
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread1").start();		

		
		//NUM=2等待时间到了,都执行接下来的任务
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await(1, TimeUnit.SECONDS);
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread0").start();
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await();
//					Thread.sleep(3000);
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread1").start();
//		
		//下面这个可能更加清楚的展示了CyclicBarrier的更合理有效的解释
//		Scanner scanner = new Scanner(System.in);
//		while(true) {
//			System.out.println("please input a number:");
//			String nextLine = scanner.nextLine();
//			if("".equals(nextLine) || nextLine == null) {
//				continue;
//			}else if("0".equals(nextLine)) {
//				System.out.println("初始化创建线程1个");
//				new Thread(new Runnable() {
//				
//					@Override
//					public void run() {
//						try {
//							System.out.println(Thread.currentThread().getName() +"-start...");
//							cyclicBarrier.await();
//							System.out.println(Thread.currentThread().getName() +"-end...");
//						} catch (InterruptedException e) {
//							e.printStackTrace();
//						} catch (BrokenBarrierException e) {
//							e.printStackTrace();
//						}
//					}
//				},"Thread0").start();
//			}else {
//				System.out.println("+1个线程");
//				new Thread(new Runnable() {
//					
//					@Override
//					public void run() {
//						try {
//							System.out.println(Thread.currentThread().getName() +"-start...");
//							cyclicBarrier.await();
//							System.out.println(Thread.currentThread().getName() +"-end...");
//						} catch (InterruptedException e) {
//							e.printStackTrace();
//						} catch (BrokenBarrierException e) {
//							e.printStackTrace();
//						}
//					}
//				},"Thread"+nextLine).start();
//			}
//			if(Thread.activeCount() == 4) {//还有一个守护线程,你知道的
//				System.out.println("结束了,不和你玩了");
//				break;
//			}
//		}
		
		//当有四个线程的时候,会发现有一个线程启动了,但是没有结束,说明在等待信号
//		new Thread(new Runnable() {
//		
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await();
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				} catch (BrokenBarrierException e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread0").start();
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await();
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				} catch (BrokenBarrierException e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread1").start();
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await();
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				} catch (BrokenBarrierException e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread2").start();
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await();
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				} catch (BrokenBarrierException e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread3").start();
		
		//三个线程执行,当三个线程全开始之后再唤醒执行下面的
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await();
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				} catch (BrokenBarrierException e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread0").start();
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await();
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				} catch (BrokenBarrierException e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread1").start();
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				try {
//					System.out.println(Thread.currentThread().getName() +"-start...");
//					cyclicBarrier.await();
//					System.out.println(Thread.currentThread().getName() +"-end...");
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				} catch (BrokenBarrierException e) {
//					e.printStackTrace();
//				}
//			}
//		},"Thread2").start();
		
	}
	
}

以上是所有测试代码运行情况的分析。 下面还有一个DEMO演示了,如果当等待时间到了,却没有打破屏障,那么此时会抛出异常, 到达打破屏障后继续执行任务。

package demo;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * CyclicBarrier测试例程
 * @ClassName:   CyclicBarrierDemo2  
 * @Description: TODO
 * @author       BurgessLee
 * @date         2019年4月30日  
 *
 */
public class CyclicBarrierDemo2 {
	
	private final static int NUM = 3;
    public static void main(String[] args){
        final CyclicBarrier barrier = new CyclicBarrier(NUM);

        for(int i=0;i<NUM;i++){
            if(i==NUM-1){//i=2
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //先休息再开启线程
                new Task(barrier).start();
            }
            else{
                new Task(barrier).start();
            }

        }

    }
    
    static class Task extends Thread{
        private CyclicBarrier barrier;
        public Task(CyclicBarrier barrier){
            this.barrier = barrier;
        }
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + "----start");
                barrier.await(3, TimeUnit.SECONDS);//等待3秒,如果所有线程3秒后还没有到达barrier,则会抛异常然后继续往下面运行
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " end");

        }

    }
	
}

通过上面的DEMO演示我们可以总结如下内容:

1.CyclicBarrier是可以重用的,但是CountDownLatch不可以。

2.如果实例化CyclicBarrier的时候,传入了第二个参数,那么在到达屏障状态之后,会调用该方法执行对应的处理,如果有异常,那么也不影响其他线程的处理。

3.如果等待超时,且未打破屏障,那么抛出异常,等待打破线程,执行后续任务。

以上就是此次针对CyclicBarrier的源码分析过程了。如果有不对的地方还请指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值