CountDownLatch和CyclicBarrier

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/u013041642/article/details/80087194

CountDownLatch

  • CountDownLatch是一个线程计数器,构造方法的参数为计数次数

    public CountDownLatch(int count) {  };  

    下面这3个方法是CountDownLatch类中最重要的方法:

public void await() throws InterruptedException { };   //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public void countDown() { };  //将count值减1
  • demo: 在主线程中latch.await(); 是主线程挂起,直至指定数目个其他线程执行完成,才继续执行主线程,保证了主线程不在其他线程执行结束前先结束。在其他线程中,每次执行调用latch.countDown(); 是线程计数器减1。从而最终实现一个性能测试的效果。
package com.susq;

import com.susq.httpclient.HttpTransport;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author susq
 * @since 2018-03-24-16:37
 */
public class TestClass {

    public static void main(String[] args) {
        CloseableHttpClient httpClient = HttpClients.createDefault();       
        String url = "http://www.baidu.com";
        moreThread(httpClient, url);
    }

    private static void moreThread(CloseableHttpClient httpClient, String url) {
        int threads = 20;
        int count = 100;
        long start = System.currentTimeMillis();
        CountDownLatch latch = new CountDownLatch(count); // 调用100次
        ExecutorService executorService = Executors.newFixedThreadPool(threads); // 线程池20
        for (int i = 0; i < count; i++) {
            executorService.execute(() -> {
                try {
                    HttpGet httpGet = new HttpGet(url);
                    CloseableHttpResponse response = httpClient.execute(httpGet);
                    int statusCode = response.getStatusLine().getStatusCode();
                    System.out.println("线程" + Thread.currentThread().getName() + "返回状态:" + statusCode);
                    response.close();
                    latch.countDown();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            //
        }
        System.out.println("cost:" + (System.currentTimeMillis() - start) + "ms");
        executorService.shutdown();
        while (!executorService.isShutdown()) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //
            }
            System.out.println("waiting...");
        }
        System.out.println("already shutdown");
    }
}

CyclicBarrier

  • ​ 字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。

    ​ 创建线程的时候,给线程类添加一个CyclicBarrier属性,run()方法中,调用CyclicBarrier的await()方法,会使当前线程挂起,进入barrier状态;直到有指定数目( parties )个线程都到达barrier状态,才继续执行这几个线程剩下的内容。如果到达barrier状态的线程数不够指定的数目parties ,那么挂起的这几个线程会一直等待。如果运行的线程数超过parties ,那么超过部分会继续监控接下来的parties 个线程,这就说明CyclicBarrier是可以重用的。

  • ​ 构造方法: parties指让多少个线程或者任务等待至barrier状态;barrierAction为当这些线程都达到barrier状态时会执行的内容。

public CyclicBarrier(int parties, Runnable barrierAction) {
}
public CyclicBarrier(int parties) {
}

例如:

package com.susq.Thread.helperclass;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @author susq
 * @since 2018-04-25-21:30
 */
public class CyclicBarrierTest {
    public static void main(String[] args) {
        int N = 4;
        CyclicBarrier barrier = new CyclicBarrier(N);
        for (int i = 0; i < 4; i++) {
            new Writer(barrier).start(); 
        }
    }

    private static class Writer extends Thread{
        private CyclicBarrier cyclicBarrier;
        public Writer(CyclicBarrier barrier) {
            this.cyclicBarrier = barrier;
        }
        @Override
        public void run() {
            System.out.println("线程" + Thread.currentThread().getName() + "正在写入数据");
            try {
                Thread.sleep(3000);
                System.out.println("线程" + Thread.currentThread().getName() + "写入完毕");
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println("所有线程写入完毕,继续执行其他任务...");
        }
    }
}

创建CyclicBarrier时构造方法中指定等待4个线程到达barrier状态时,继续执行。同时我们也创建了四个线程,程序运行等待4个线程都到达barrier时,这几个线程才执行剩下的部分,顺利执行结束。输出如下:

线程Thread-0正在写入数据
线程Thread-1正在写入数据
线程Thread-2正在写入数据
线程Thread-3正在写入数据
线程Thread-0写入完毕
线程Thread-1写入完毕
线程Thread-2写入完毕
线程Thread-3写入完毕
所有线程写入完毕,继续执行其他任务…
所有线程写入完毕,继续执行其他任务…
所有线程写入完毕,继续执行其他任务…
所有线程写入完毕,继续执行其他任务…

但是如果创建不是4的倍数个线程,每当有4个线程到达barrier状态是,这四个线程执行剩下的部分,完成。但是最后剩下的线程数不够四个,就会一直挂起等待,比如我们修改上面程序,创建10个线程,只有8个能执行完,输出如下:

线程Thread-0正在写入数据
线程Thread-2正在写入数据
线程Thread-1正在写入数据
线程Thread-3正在写入数据
线程Thread-4正在写入数据
线程Thread-6正在写入数据
线程Thread-7正在写入数据
线程Thread-8正在写入数据
线程Thread-9正在写入数据
线程Thread-5正在写入数据
线程Thread-0写入完毕
线程Thread-2写入完毕
线程Thread-1写入完毕
线程Thread-3写入完毕
所有线程写入完毕,继续执行其他任务…
所有线程写入完毕,继续执行其他任务…
所有线程写入完毕,继续执行其他任务…
所有线程写入完毕,继续执行其他任务…
线程Thread-4写入完毕
线程Thread-6写入完毕
线程Thread-7写入完毕
线程Thread-9写入完毕
线程Thread-8写入完毕
所有线程写入完毕,继续执行其他任务…
所有线程写入完毕,继续执行其他任务…
所有线程写入完毕,继续执行其他任务…
所有线程写入完毕,继续执行其他任务…
线程Thread-5写入完毕

  • await(long timeout, TimeUnit unit)

    等待指定的时候之后,无论到达barrier状态的线程数目是否足够我们指定的数目,都继续执行。只不过会抛出异常,但不影响剩余部分的执行

  • 例如

    下面代码中需要4个线程到达barrier状态,或者等待指定的时间(2秒)以后继续执行,而第四个线程在前三个线程运行5面后再创建,所以前面三个线程等待结束后会先执行完,同时抛出异常。

    package com.susq.Thread.helperclass;
    
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.TimeoutException;
    
    /**
    * @author susq
    * @since 2018-04-25-21:30
    */
    public class CyclicBarrierTest {
      public static void main(String[] args) {
          int N = 4;
          CyclicBarrier barrier = new CyclicBarrier(N);
          for (int i = 0; i < 3; i++) {
              new Writer(barrier).start();
          }
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          new Writer(barrier).start();
      }
    
      private static class Writer extends Thread{
          private CyclicBarrier cyclicBarrier;
          public Writer(CyclicBarrier barrier) {
              this.cyclicBarrier = barrier;
          }
          @Override
          public void run() {
              System.out.println("线程" + Thread.currentThread().getName() + "正在写入数据");
              try {
                  Thread.sleep(3000);
                  System.out.println("线程" + Thread.currentThread().getName() + "写入完毕");
                  cyclicBarrier.await(2, TimeUnit.SECONDS);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              } catch (BrokenBarrierException e) {
                  e.printStackTrace();
              } catch (TimeoutException e) {
                  e.printStackTrace();
              }
              System.out.println("所有线程写入完毕,继续执行其他任务...");
          }
      }
    }

    输出:

    线程Thread-0正在写入数据
    线程Thread-1正在写入数据
    线程Thread-2正在写入数据
    线程Thread-0写入完毕
    线程Thread-1写入完毕
    线程Thread-2写入完毕
    线程Thread-3正在写入数据
    java.util.concurrent.BrokenBarrierException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
    at com.susq.Thread.helperclass.CyclicBarrierTest Writer.run(CyclicBarrierTest.java:39)java.util.concurrent.BrokenBarrierExceptionatjava.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)atjava.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)atcom.susq.Thread.helperclass.CyclicBarrierTest Writer.run(CyclicBarrierTest.java:39)
    java.util.concurrent.TimeoutException
    at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:257)
    at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
    at com.susq.Thread.helperclass.CyclicBarrierTest Writer.run(CyclicBarrierTest.java:39)线线线线Thread3java.util.concurrent.BrokenBarrierException线atjava.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)atjava.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)atcom.susq.Thread.helperclass.CyclicBarrierTest Writer.run(CyclicBarrierTest.java:39)

猜你喜欢

转载自blog.csdn.net/u013041642/article/details/80087194