자바 Count Downlatch 와 Cyclic Barrier 의 내부 실현 과 장면 상의 차 이 를 상세히 설명 합 니 다.

머리말
Countdown Latch 와 CyclicBarrier 는 자바 병행 프로 그래 밍 의 중요 한 도구 류 로 여러 스 레 드 병행 또는 병행 장면 에서 광범 위 하 게 응용 되 었 다.그러나 이들 은 내부 실현 과 사용 장면 에 있어 각각 중점 을 두 고 있다.
내부 구현 차이
전 자 는 전형 적 인 AQS 체제 와 CAS 체제 에 의존 하여 내부 상태의 교체 와 카운터 자체 의 변 화 를 컨트롤 하고 후 자 는 Lock 등 체제 에 다시 들 어가 내부 의 병행 안전성 과 일치 성 을 컨트롤 한다.

 public class {
   //Synchronization control For CountDownLatch.
   //Uses AQS state to represent count.
  private static final class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 4982264981922014374L;

    Sync(int count) {
      setState(count);
    }

    int getCount() {
      return getState();
    }

    protected int tryAcquireShared(int acquires) {
      return (getState() == 0) ? 1 : -1;
    }

    protected boolean tryReleaseShared(int releases) {
      // Decrement count; signal when transition to zero
      for (;;) {
        int c = getState();
        if (c == 0)
          return false;
        int nextc = c-1;
        if (compareAndSetState(c, nextc))
          return nextc == 0;
      }
    }
  }

  private final Sync sync;
  ... ...//
 }

 public class CyclicBarrier {
  /**
   * Each use of the barrier is represented as a generation instance.
   * The generation changes whenever the barrier is tripped, or
   * is reset. There can be many generations associated with threads
   * using the barrier - due to the non-deterministic way the lock
   * may be allocated to waiting threads - but only one of these
   * can be active at a time (the one to which {@code count} applies)
   * and all the rest are either broken or tripped.
   * There need not be an active generation if there has been a break
   * but no subsequent reset.
   */
  private static class Generation {
    boolean broken = false;
  }

  /** The lock for guarding barrier entry */
  private final ReentrantLock lock = new ReentrantLock();
  /** Condition to wait on until tripped */
  private final Condition trip = lock.newCondition();
  /** The number of parties */
  private final int parties;
  /* The command to run when tripped */
  private final Runnable barrierCommand;
  /** The current generation */
  private Generation generation = new Generation();

  /**
   * Number of parties still waiting. Counts down from parties to 0
   * on each generation. It is reset to parties on each new
   * generation or when broken.
   */
  private int count;

  /**
   * Updates state on barrier trip and wakes up everyone.
   * Called only while holding lock.
   */
  private void nextGeneration() {
    // signal completion of last generation
    trip.signalAll();
    // set up next generation
    count = parties;
    generation = new Generation();
  }

  /**
   * Sets current barrier generation as broken and wakes up everyone.
   * Called only while holding lock.
   */
  private void breakBarrier() {
    generation.broken = true;
    count = parties;
    trip.signalAll();
  }

  /**
   * Main barrier code, covering the various policies.
   */
  private int dowait(boolean timed, long nanos)
    throws InterruptedException, BrokenBarrierException,
        TimeoutException {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
      final Generation g = generation;

      if (g.broken)
        throw new BrokenBarrierException();

      if (Thread.interrupted()) {
        breakBarrier();
        throw new InterruptedException();
      }

      int index = --count;
      if (index == 0) { // tripped
        boolean ranAction = false;
        try {
          final Runnable command = barrierCommand;
          if (command != null)
            command.run();
          ranAction = true;
          nextGeneration();
          return 0;
        } finally {
          if (!ranAction)
            breakBarrier();
        }
      }

      // loop until tripped, broken, interrupted, or timed out
      for (;;) {
        try {
          if (!timed)
            trip.await();
          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.
            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();
    }
  }
  ... ... //
 }
실전.-각자 의 사용처 보 여주 기.

/**
 *   : 5       ,6      ,     ,              
 */
public class UseCountDownLatch {
  
  static CountDownLatch latch = new CountDownLatch(6);

  /*     */
  private static class InitThread implements Runnable{

    public void run() {
      System.out.println("Thread_"+Thread.currentThread().getId()
         +" ready init work......");
      latch.countDown();
      for(int i =0;i<2;i++) {
        System.out.println("Thread_"+Thread.currentThread().getId()
           +" ........continue do its work");
      }
    }
  }

  /*      latch     0  */
  private static class BusiThread implements Runnable{

    public void run() {
      try {
        latch.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      for(int i =0;i<3;i++) {
        System.out.println("BusiThread_"+Thread.currentThread().getId()
           +" do business-----");
      }
    }
  }

  public static void main(String[] args) throws InterruptedException {
    new Thread(new Runnable() {
      public void run() {
        SleepTools.ms(1);
        System.out.println("Thread_"+Thread.currentThread().getId()
           +" ready init work step 1st......");
        latch.countDown();
        System.out.println("begin step 2nd.......");
        SleepTools.ms(1);
        System.out.println("Thread_"+Thread.currentThread().getId()
           +" ready init work step 2nd......");
        latch.countDown();
      }
    }).start();
    new Thread(new BusiThread()).start();
    for(int i=0;i<=3;i++){
      Thread thread = new Thread(new InitThread());
      thread.start();
    }
    latch.await();
    System.out.println("Main do ites work........");
  }
}

/**
 *   : 4    ,         ,      ,
 *             ,                   
 */
class UseCyclicBarrier {
  private static CyclicBarrier barrier
      = new CyclicBarrier(4,new CollectThread());

  //            
  private static ConcurrentHashMap<String,Long> resultMap
      = new ConcurrentHashMap<String,Long>();

  public static void main(String[] args) {
    for(int i=0;i<4;i++){
      Thread thread = new Thread(new SubThread());
      thread.start();
    }

  }

  /*     */
  private static class CollectThread implements Runnable{

    @Override
    public void run() {
      StringBuilder result = new StringBuilder();
      for(Map.Entry<String,Long> workResult:resultMap.entrySet()){
        result.append("["+workResult.getValue()+"]");
      }
      System.out.println(" the result = "+ result);
      System.out.println("do other business........");
    }
  }

  /*        */
  private static class SubThread implements Runnable{
    @Override
    public void run() {
      long id = Thread.currentThread().getId();
      resultMap.put(Thread.currentThread().getId()+"",id);
      try {
          Thread.sleep(1000+id);
          System.out.println("Thread_"+id+" ....do something ");
        barrier.await();
        Thread.sleep(1000+id);
        System.out.println("Thread_"+id+" ....do its business ");
        barrier.await();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}


 양자 총화
1.Cyclicbarrier 결 과 를 모 은 Runable 스 레 드 는 반복 적 으로 실 행 될 수 있 습 니 다.await()방법 을 여러 번 터치 하면 countdownlatch 는 await()방법 을 여러 번 호출 할 수 있 습 니 다.cyclicbarrier 가 결 과 를 모 으 지 않 으 면 await()를 한 번 호출 하면 됩 니 다.
2.New cyclicbarrier(threadCount)의 스 레 드 수 는 실제 사용자 스 레 드 수 와 일치 해 야 합 니 다.
3.조정 스 레 드 동시 운행:countDownlatch 조정 작업 스 레 드 실행,외부 스 레 드 조정;cyclicbarrier 는 작업 스 레 드 간 에 서로 조 화 롭 게 운행 합 니 다.
4.구조 함수 에서 볼 수 있 듯 이 countDownlatch 가 실행 하 는 계수기 의 수량 은 스 레 드 수 와 관계 가 없습니다.cyclicbarrier 구조 에서 들 어 오 는 스 레 드 수 는 실제 실행 스 레 드 수 와 같 습 니 다.
5.countDownlatch 는 하위 스 레 드 의 실행 결 과 를 기반 으로 처리 할 수 없 으 며,cyclicbarrier 는 가능 합 니 다.
6.장면 을 사용 할 때 countdownlatch 는 프레임 워 크 로 딩 전의 일련의 초기 화 작업 등 장면 에 더욱 적합 합 니 다.cyclicbarrier 는 여러 사용자 스 레 드 가 실 행 된 후에 실행 결 과 를 종합 하여 계산 하 는 등 전형 적 인 장면 에 더욱 적합 합 니 다.
자바 Count Downlatch 와 Cyclic Barrier 의 내부 구현 과 장면 상의 차 이 를 상세히 설명 하 는 글 을 소개 합 니 다.자바 Count Downlatch 와 Cyclic Barrier 의 차이 점 에 대해 서 는 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!

좋은 웹페이지 즐겨찾기