EffectiveJava第十章第四节

并发工具优先与wait和notify

java.util.concurrent中更高级的工具分成三类:Executor Framework并发集合(Concurrent Collection)以及同步器(Synchronizer)。相比于java.util中提供的集合类,java.util.concurrent中提供的并发集合就有更好的并发性,其性能通常数倍于普通集合,如ConcurrentHashMap等。换句话说,除非有极其特殊的原因存在,否则在并发的情况下,一定要优先选择ConcurrentHashMap,而不是Collections.syschronizedmap或者Hashtable

java.util.concurrent包中还提供了阻塞队列,该队列极大的简化了生产者线程和消费者线程模型的编码工作。

对于同步器,concurrent包中给出了四种主要的同步器对象:CountDownLatchSemaphoreCyclicBarrierExchanger。这里前两种比较常用。在该条目中我们只是简单介绍一个CountDownLatch的优势,该类允许一个或者多个线程等待一个或者多个线程来做某些事情。CountDownLatch的唯一构造函数带有一个int类型的参数 ,这个int参数是指允许所有在等待的线程被处理之前,必须在锁存器上调用countDown方法的次数。

现在我们给出一个简单应用场景,然后再给出用CountDownLatch实现该场景的实际代码。场景描述如下:
  假设想要构建一个简单的框架,用来给一个动作的并发执行定时。这个框架中包含单个方法,这个方法带有一个执行该动作的executor,一个并发级别(表示要并发执行该动作的次数),以及表示该动作的runnable。所有的工作线程自身都准备好,要在timer线程启动时钟之前运行该动作。当最后一个工作线程准备好运行该动作时,timer线程就开始执行,同时允许工作线程执行该动作。一旦最后一个工作线程执行完该动作,timer线程就立即停止计时。直接在waitnotify之上实现这个逻辑至少来说会很混乱,而在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();  
           }  
       }  
   }  
}  

你可能感兴趣的:(EffectiveJava第十章第四节)