并发库之CountDownLatch

来源:互联网 发布:单片机设计实例 编辑:程序博客网 时间:2024/05/22 11:43

允许一个或多个线程等待其他线程完成某一步操作。

需求1:

如果有三个线程,主线程,Thread1,Thread2.假设主线程必须等待线程1和线程2执行完毕,它才能继续往下执行。我们可能首先考虑到的是使用join方法。

publicclass JoinClient {

      public static void main(String[] args) throwsInterruptedException {

           Threadt1 =new Thread(new Runnable() {

                @Override

                publicvoid run() {

                      System.out.println("nicky");

                      System.out.println("belly");

                 }

           },"Thread1");

           Threadt2 =new Thread(new Runnable() {

                @Override

                publicvoid run() {

                      System.out.println("avria");

                 }

           },"Thread2");

          t1.start();

          t2.start();

          t1.join();//等待線程1執行完畢

          t2.join();//等待線程2執行完畢

           System.out.println("All ThreadRunned!");

      }

}

输出结果:

nicky

avria

belly

All Thread Runned!

我们可以看到主线程是在等待线程1和线程2执行完毕之后才执行的。

需求2:如果主线程只需要等待线程里面某一个代码执行片段执行完毕,则就可以往下执行了。这时候Join就不适用了,因为Join只能等待线程执行完毕,线程已经不存活。这时候CountDownLatch就可以派上用场了。

CountDownLatch构造函数需要接受一个int类型的数值,传入的数值依据你希望有几个点完成之后,然后等待的线程就可以继续执行,否则就继续等。而且这个数值不能为空。

当我们调用一次CountDownLatch.countDown方法,这个数值就会减一。一直到为0,表示所有的点都已经过了。然后等待的线程可以继续执行了。

那是什么来检测这个值为0呢?这就是需要调用CountDownLatch.

await方法,它会阻塞当前线程,直到这个数值为0. 有时候可能某得线程执行的很慢,我们在等了一定的时间后,不想继续等下去,那么你可以设定一个值。await(long, TimeUnit ) 等待一定时间后,不等了。不阻塞等待的线程了。

publicclassCountDownLatchClient {

      private static CountDownLatch cdl =newCountDownLatch(2);

      public static void main(String[] args) throwsInterruptedException {

          new Thread(new Runnable() {

                @Override

                publicvoid run() {

                      System.out.println("nicky");

                     cdl.countDown();

                      System.out.println("belly");

                 }

           },"Thread1").start();

          

          new Thread(new Runnable() {

                @Override

                publicvoid run() {

                      System.out.println("avria");

                     cdl.countDown();

                 }

           },"Thread2").start();

          

          cdl.await();//等待所有線程完成

           System.out.println("All ThreadRunned!");

      }

}

输出结果:

nicky

belly

avria

All Thread Runned!

如果我现在有三个地方调用countDown方法,但是数值我们还是设置的2.

看看输出结果:

publicclassCountDownLatchClient {

      private static CountDownLatch cdl =newCountDownLatch(2);

      public static void main(String[] args) throwsInterruptedException {

          new Thread(new Runnable() {

                @Override

                publicvoid run() {

                      System.out.println("nicky");

                     cdl.countDown();

                      System.out.println("belly");

                     cdl.countDown();

                 }

           },"Thread1").start();

          

          new Thread(new Runnable() {

                @Override

                publicvoid run() {

                      System.out.println("avria");

                     cdl.countDown();

                 }

           },"Thread2").start();

          

          cdl.await();//等待所有線程完成

           System.out.println("All ThreadRunned!");

      }

}

输出结果:

nicky

belly

All Thread Runned!

Avria

我们可以看到avria并没有在All Thread Runned!之前输出吧。为什么?因为countDown已经调用了2此,这时候await方法已经不阻塞了。

 

我们在看看 等待一段时间,就不阻塞的情况:

publicclassCountDownLatchClient {

      private static CountDownLatch cdl =newCountDownLatch(3);

      public static void main(String[] args) throwsInterruptedException {

          new Thread(new Runnable() {

                @Override

                publicvoid run() {

                     try {

                            Thread.sleep(3000);

                      }catch(InterruptedExceptione) {

                           e.printStackTrace();

                      }

                      System.out.println("nicky");

                     cdl.countDown();

                      System.out.println("belly");

                     cdl.countDown();

                 }

           },"Thread1").start();

 

          new Thread(new Runnable() {

                @Override

                publicvoid run() {

                      System.out.println("avria");

                     cdl.countDown();

                 }

           },"Thread2").start();

          

          cdl.await(2,TimeUnit.SECONDS);//等待所有線程完成

           System.out.println("All ThreadRunned!");

      }

}

 

现在我们再看输出结果:

avria

All Thread Runned!

nicky

belly

 

注意:一般情况下我们都会把countDown放在finally,确保她无论如何也必须执行。

Join 和 CountDownLatch比较

Join: 是不断的去检测线程是否还活着,如果还活着继续阻塞,否则,就调用this.notifyAll,唤醒当前线程。

CountDownLatch:

他提供了更加灵活的控制,不仅可以等待线程执行完毕,还可以在执行某一步操作的时候,就让等待的线程不用等了。


原创粉丝点击