java 多线程编程 CountDownLatch(线程计数器) 和 CyclicBarrier 的用法

CountDownLatch - 线程计数器

包名:java.util.concurrent

功能:

多线程编程中,要并发请求10个接口,等这些接口都返回结果再进行统一处理后,将结果返回。

调用countDown() 方法 ,计数减去 1。

代码示例

调用countDown()方法后,会执行下面的源码

java 多线程编程 CountDownLatch(线程计数器) 和 CyclicBarrier 的用法_第1张图片

 

//此处需要maven 引入 commons-lang3 包
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.annotation.Async;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
public class LockTest {

final CountDownLatch cdl = new CountDownLatch(10);

   @Test
    void testLatch() throws InterruptedException {
        //定义固定线程池
        ExecutorService exec = Executors.newFixedThreadPool(10);
        List list = new ArrayList<>();
        //统计执行时间
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        for (int i = 0; i < 10; i++) {
            exec.execute(new Runnable() {
                @Override
                public void run() {
                    int sleep = RandomUtils.nextInt(1,10);
                    try {
                        System.out.println("当前线程:" + Thread.currentThread().getName() + ",休眠:" + sleep);
                        //此处模拟请求外部接口
                        TimeUnit.SECONDS.sleep(sleep);
                        //此处模拟返回结果
                        list.add(Thread.currentThread().getName() + "-" + sleep);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    //执行完一次,从计数器中释放线程
                    cdl.countDown();
                }
            });
        }
        //等待所有线程执行完
        cdl.await();

        //统一处理结果
        for (String s : list) {
            System.out.println(s);
        }
        stopWatch.stop();
        System.out.println("总计耗时:" + stopWatch.getTime() + "ms");
    }
}

执行结果:

当前线程:pool-1-thread-8,休眠:1
当前线程:pool-1-thread-2,休眠:3
当前线程:pool-1-thread-9,休眠:9
当前线程:pool-1-thread-7,休眠:2
当前线程:pool-1-thread-4,休眠:8
当前线程:pool-1-thread-3,休眠:4
当前线程:pool-1-thread-1,休眠:5
当前线程:pool-1-thread-6,休眠:7
当前线程:pool-1-thread-10,休眠:4
当前线程:pool-1-thread-5,休眠:6
pool-1-thread-8-1
pool-1-thread-7-2
pool-1-thread-2-3
pool-1-thread-10-4
pool-1-thread-3-4
pool-1-thread-1-5
pool-1-thread-5-6
pool-1-thread-6-7
pool-1-thread-4-8
pool-1-thread-9-9
总计耗时:9010ms

CyclicBarrier - 等待至barrier状态再全部同时执行(回环栅栏)

包名:java.util.concurrent

功能:

一组线程,等待他们各自执行完操作并且都调用 await() 方法,再同时执行各自后续的任务。

代码示例:

//此处需要maven 引入 commons-lang3 包
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.annotation.Async;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
public class LockTest {

    CyclicBarrier barrier = new CyclicBarrier(5);

    @Test
    void testBarrier() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            //启动5个线程
            new Tests(barrier).start();
        }
        Thread.sleep(5000);
        System.out.println("继续操作");
    }

    static class Tests extends Thread {
        CyclicBarrier cyclicBarrier;
        Tests(CyclicBarrier barrier) {
            cyclicBarrier = barrier;
        }

        @Override
        public void run() {
            //模拟执行代码时长
            int r = RandomUtils.nextInt(1,5);
            System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + "线程休眠:" + Thread.currentThread().getName() + ": " + r + "s");
            try {
                TimeUnit.SECONDS.sleep(r);
                //调用await()方法,线程处于barrier,等待所有线程都调用await()方法
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (BrokenBarrierException e) {
                throw new RuntimeException(e);
            }
            //所有线程都调用await()方法后,执行后续的代码
            System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " 所有执行完成,继续向下执行: " + Thread.currentThread().getName());
        }

    }
}

执行结果:

2023-08-31 12:32:46线程休眠:Thread-2: 3s
2023-08-31 12:32:46线程休眠:Thread-4: 4s
2023-08-31 12:32:46线程休眠:Thread-3: 1s
2023-08-31 12:32:46线程休眠:Thread-1: 3s
2023-08-31 12:32:46线程休眠:Thread-5: 1s
2023-08-31 12:32:50 所有执行完成,继续向下执行: Thread-4
2023-08-31 12:32:50 所有执行完成,继续向下执行: Thread-1
2023-08-31 12:32:50 所有执行完成,继续向下执行: Thread-5
2023-08-31 12:32:50 所有执行完成,继续向下执行: Thread-3
2023-08-31 12:32:50 所有执行完成,继续向下执行: Thread-2
继续操作

结论

相同点:


CountDownLatch 和 CyclicBarrier 都能够实现线程之间的等待


区别


CountDownLatch 一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行
CyclicBarrier 一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行
CountDownLatch 是不能够重用的,而 CyclicBarrier 是可以重用的。

你可能感兴趣的:(java,多线程,java)