Thinking in 자바-Concurrent 패키지 의 새로운 구성 요소 학습+경마 게임 시 뮬 레이 션

15910 단어 ThinkinginJava
자바 5 의 자바 util.concurrent 패키지 에 병발 문 제 를 해결 하 는 새로운 종 류 를 대량으로 도입 하 였 습 니 다.앞의 기본 적 인 스 레 드 동기 화 와 통신 방법 에 비해 이런 새로운 종 류 는 더욱 높 은 차원 의 추상 적 이 고 사용 하기 쉬 운 것 입 니 다.이 블 로 그 는 그 중의 두 가지 새로운 종 류 를 배 웁 니 다.CountDownlatch 와 Cyclic Barrier;그리고 Cyclic Barrier 를 사용 하여 간단 한 경마 게임 을 모 의 합 니 다.
1.countDownlatch 가 Countdownlatch 대상 을 사용 할 때 초기 계수 값 을 설정 한 다음 이 대상 에서 await()를 호출 하 는 작업 은 이 대상 의 계수 값 이 0 으로 줄 어 들 때 까지 막 힙 니 다.다른 임 무 는 자신의 일 을 완성 할 때 이 대상 의 countDown()방법 을 사용 하여 이 대상 의 계산 치 를 줄 일 수 있 습 니 다.따라서 이 종 류 는 하나 이상 의 작업 을 동기 화하 고 다른 작업 이 실 행 될 때 까지 기다 리 도록 강제 할 수 있 습 니 다.하나의 전형 적 인 응용 장면 은 하나의 프로그램 을 n 개의 서로 독립 된 해결 가능 한 작업 으로 분해 하고 n 의 Countdown Latch 를 만 드 는 것 입 니 다.모든 작업 이 완 료 될 때 이 대상 에서 countDown()을 호출 합 니 다.이 문제 가 해결 되 기 를 기다 리 는 작업 은 이 대상 에서 await()를 호출 하여 이 대상 의 계수 값 이 0 으로 줄 어 들 때 까지 차단 합 니 다.또 주의해 야 할 것 은 이 대상 이 n 개 임무 수행 의 우선 순 위 를 조율 하지 않 는 다 는 점 이다.다음은 이 기술 의 프레임 워 크 예 시 를 보 여 줍 니 다.
package lkl;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * CountDownLatch           ,    
 *                 
 * */

//       
class TaskPortion implements Runnable{
      private static int counter = 0;
      private final int id= counter++;

      //          Random  ,             
      //     Random.next()         ,             
      private static Random rand = new Random(47);

      private final CountDownLatch latch;
      public TaskPortion(CountDownLatch latch){
          this.latch = latch;
      }

      public void run(){
          try{
              dowork();
              latch.countDown(); //     
          }catch(InterruptedException ex){
              System.out.println(this+"         ");  
          }
      }

      //              
     public void dowork() throws InterruptedException{
         TimeUnit.MILLISECONDS.sleep(rand.nextInt(2000));
         System.out.println(this+" completed");
     }

     public String toString(){
         return String.format("%1$-3d", id);
     }
}

class WaitingTask implements Runnable{
    private static int counter = 0;
    private final CountDownLatch latch;
    private final int id = counter++;
    public WaitingTask(CountDownLatch latch){
        this.latch = latch;
    }
    public void run()  {
        try{
            latch.await();; // latch       0  ,       
            System.out.println(this+" completed");
        }catch(InterruptedException ex){
            System.out.println();
        }
    }
    public String toString(){
        return String.format("WatitingTask %1$-3d", id);
    }
}

public class CountDownLatchDemo {

    static final int SIZE = 100;
    public static void main(String[] args) throws Exception{
        ExecutorService exec = Executors.newCachedThreadPool();

        //           latch  
        //        100,     100       
        //        await()       
       CountDownLatch latch = new CountDownLatch(SIZE);

       // 10     
       for(int i=0; i<10; i++){
           exec.execute(new WaitingTask(latch));
       }

       // 100        
       for(int i=0; inew TaskPortion(latch));
       }
       System.out.println("Latched all takss");
       exec.shutdown();
    }
}

2.cyclicbarrier Cyclicbarrier 는 이러한 상황 에 적 용 됩 니 다.우 리 는 하나의 작업 을 만 들 고 다음 단 계 를 진행 하기 전에 모든 작업 이 완 료 될 때 까지 기다 리 고 싶 습 니 다.(정상 적 인 스 레 드 에 따라 스케줄 링 을 하 는 것 은 불가능 합 니 다)그것 은 모든 임 무 를 울타리 에 줄 을 서 게 하기 때문에 일치 하 게 앞으로 이동 할 수 있다.이것 은 위의 Countdown Latch 와 유사 해 보이 지만 Countdown Latch 는 한 번 만 이벤트 가 발생 할 수 있 습 니 다.CyclicBarrier 는 여러 번 다시 사용 할 수 있 습 니 다.더 구체 적 인 사용 은 다음 과 같 습 니 다.우 리 는 초기 계수 값 을 n 과 Runnable 대상 을 r 로 지정 한 CyclicBarrier 이미 지 를 만 든 다음 n 개의 스 레 드 에 제출 합 니 다.모든 스 레 드 는 현재 작업 을 완료 한 후에 이 대상 의 await()를 호출 하여 계수 값 을 줄 이 고 현재 스 레 드 가 막 힙 니 다.이렇게 하면 마지막 스 레 드 가 await()를 호출 하여 계수 값 을 0 으로 줄 인 다음 에 이 Cyclibarrier 대상 의 r run()방법 을 호출 합 니 다.run()방법 이 실 행 된 후에 Cyclic Barrier 대상 의 계수 값 을 리 셋 한 다음 에 위의 과정 을 반복 합 니 다.이러한 과정 을 통 해 여러 스 레 드 를 일치 하 게 앞으로 이동 시 키 는 효과 가 있다.다음은 이 종 류 를 사용 하여 경마 게임 을 모방 합 니 다.
package lkl;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 *       
 *         "*"          ,  "=="    
 *       :              ,            
 *                      ;    CyclicBarrier       
 *            ,         。    CycylicBarrier run()   
 *             。
 *                   ,         。
 * */

//      
class Horse implements Runnable{
    private static int counter = 1;
    private final int id = counter++;//    
    private int strides = 0; //        
    private static Random rand = new Random(47);
    private static CyclicBarrier barrier;//        CyclicBarrier  

    public Horse(CyclicBarrier b){
        barrier = b;
    }
    //          
    public synchronized int getStrides(){
        return strides;
    }

    public void run(){
        try
        {
            while(!Thread.interrupted()){
                synchronized(this){
                    //        
                    strides+=rand.nextInt(3); //0,1,2
                }
            //                  
            //       barrier run()  ,              ,        
            //                        ,          
            //           ,             。           
            //       ,      。
            barrier.await();
            }
        }
        catch(InterruptedException ex){
            System.out.println(this+ "         ");
        }catch(BrokenBarrierException e){//await()     
            throw new RuntimeException();
        }
    }
    public String toString(){
        return "Horse "+id+" ";
    }
    //  "*"        
    public String tracks(){
        StringBuilder s = new StringBuilder();
        for(int i=0 ;i"*");
        }
        s.append(id);
        return s.toString();
    }
}

public class HorseRace {

      static final int FINISH_LINE=75; //     
      private List horses = new ArrayList();
      private ExecutorService exec = Executors.newCachedThreadPool();
      private CyclicBarrier barrier;

      public HorseRace(int nHorse,final int pause){

          //  CyclicBarrier         Runnable         0   
          //  ,               。     Runnable      
          //                。
          barrier = new CyclicBarrier(nHorse,new Runnable(){
              public void run(){

                  StringBuilder s = new StringBuilder();
                  //    
                  for(int i=0 ; i"=");
                  }
                  System.out.println(s);
                  //          (“*”+id  )
                  for(Horse horse : horses){
                      System.out.println(horse.tracks());
                  }

                  //           ,         
                  //     (          )
                  for(Horse horse: horses){
                      if(horse.getStrides()>=FINISH_LINE){
                          System.out.println(horse+" won");
                          exec.shutdownNow();
                          return;
                      }
                  }
                  try{
                      //      
                      TimeUnit.MILLISECONDS.sleep(pause);
                  }catch(InterruptedException ex){
                      ex.printStackTrace();
                  }
              }
          });

          //  nHorse    
         for(int i=0; inew Horse(barrier);
             horses.add(horse);
             exec.execute(horse);
         }
      }

      public static void main(String[] args){
          //  7    
          int nHorses = 7;
          int pause = 200;
          new HorseRace(nHorses,pause);
      }
}

좋은 웹페이지 즐겨찾기