EffectiveJava第10章第4節

3799 ワード

同時ツール優先waitとnotify


java.util.concurrentのより高度なツールは、Executor Framework、コンカレントコレクション、Synchronizerの3つに分類されます.Javaに比べて.utilで提供される集合クラスjava.util.concurrentで提供されるコンカレントセットは、コンカレントHashMapなどの通常のセットの数倍のパフォーマンスを有するより良いコンカレント性を有する.すなわち、極めて特殊な理由がない限り、同時の場合、CollectionsではなくConcurrentHashMapを優先的に選択しなければならない.SyschronizedmapまたはHashtable.
java.util.concurrentパケットには、生産者スレッドと消費者スレッドモデルの符号化作業を極めて簡素化するブロックキューも提供される.
同期器の場合、concurrentパッケージには、CountDownLatch、Semaphore、CyclicBarrier、Exchangerの4つの主要な同期器オブジェクトが表示されます.ここでは前の2種類がよく使われています.このエントリでは、1つ以上のスレッドが1つ以上のスレッドを待って何かをすることができるCountDownLatchの利点を簡単に紹介します.CountDownLatchの一意のコンストラクション関数には、待機中のスレッドが処理される前に、ラッチ上でcountDownメソッドを呼び出す必要があるすべての回数を許可するintタイプのパラメータがあります.
ここでは、単純な適用シーンを示し、CountDownLatchでそのシーンを実装する実際のコードを示します.シーンの説明は、単純なフレームワークを構築して、動作の同時実行タイミングを与えると仮定します.このフレームワークには、動作を実行するexecutor、動作を同時に実行する回数を示す同時レベル、および動作を表すrunnableを有する単一のメソッドが含まれています.すべてのワークスレッド自体が準備されており、timerスレッドがクロックを開始する前に動作を実行します.最後のワークスレッドが動作を実行する準備ができている場合、timerスレッドは実行を開始し、ワークスレッドが動作を実行できるようにします.最後のワークスレッドが実行されると、timerスレッドはすぐにタイミングを停止します.この論理はwaitとnotifyの上で直接実現するのは少なくとも混乱するが,CountDownLatchの上で実現するのはかなり簡単である.次のコードの例を示します.
public static long time(Executor executor,int concurrency,final Runnable action) {
       final CountDownLatch ready = new CountDownLatch(concurrency);
       final CountDownLatch start = new CountDownLatch(1);
       final CountDownLatch done = new CountDownLatch(concurrency);
       for (int i = 0; i < concurrency; i++) {
           executor.execute(new Runnable() {
               public void run() {
                   ready.countDown();
                   try {
                       start.await();
                       action.run();
                   } catch (InterruptedException e) {
                       Thread.currentThread().interrupt();
                   } finally {
                       done.countDown();
                   }
               }
           });
           // , ready.countDown() 。
           ready.await(); 
           // nanoTime, System.currentTimeMills()。
           long startNanos = System.nanoTime();
           // , start.await() 。
           start.countDown();
           // , done.countDown() 。
           done.await();
           return System.nanoTime() - startNanos;
       }
   }
public class CountDownLatchDemo {  
   final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
   public static void main(String[] args) throws InterruptedException {  
       CountDownLatch latch=new CountDownLatch(2);//   
       Worker worker1=new Worker("zhang san", 5000, latch);  
       Worker worker2=new Worker("li si", 8000, latch);  
       worker1.start();//  
       worker2.start();//  
       latch.await();//   
       System.out.println("all work done at "+sdf.format(new Date()));  
   }  
     
     
   static class Worker extends Thread{  
       String workerName;   
       int workTime;  
       CountDownLatch latch;  
       public Worker(String workerName ,int workTime ,CountDownLatch latch){  
            this.workerName=workerName;  
            this.workTime=workTime;  
            this.latch=latch;  
       }  
       public void run(){  
           System.out.println("Worker "+workerName+" do work begin at "+sdf.format(new Date()));  
           doWork();//   
           System.out.println("Worker "+workerName+" do work complete at "+sdf.format(new Date()));  
           latch.countDown();// ,   
 
       }  
         
       private void doWork(){  
           try {  
               Thread.sleep(workTime);  
           } catch (InterruptedException e) {  
               e.printStackTrace();  
           }  
       }  
   }  
}