J.U.C常见的并发工具集-Countdownlatch、Cyclicbarrier、Semaphore、Exchanger

J.U.C常见的并发工具集

以下是学习中的一些笔记记录,如果有错误希望得到你的指正~ 同时也希望对你有点帮助~

Countdownlatch

共享锁的实现,可以允许多个线程同时抢占到锁,然后等到计数器归零的时候,同时唤醒持有锁的线程

  • 阻塞一个线程

/**
 * CountDownLatch 就相当于是一个计数器,当计数归0,释放所有被阻塞的线程,通过AQS共享锁实现
 *
 * CountDownLatch quick start 子线程countdown main线程 await
 * 所有子线程执行完之后countdown计数为0,才执行main线程,阻塞一个线程
 *
 * @author zdp
 * @date 2022-06-02 10:03
 */
public class CountDownLatchTestOne {

    static CountDownLatch countDownLatch = new CountDownLatch(2);

    public static void main(String[] args) throws InterruptedException {
        ThreadOne one = new ThreadOne();
        ThreadTwo two = new ThreadTwo();
        one.start();
        two.start();
        System.out.println("main 线程阻塞....");
        countDownLatch.await();
        System.out.println("main 线程释放....");
    }

    static class ThreadOne extends Thread {
        @Override
        @SneakyThrows
        public void run() {
            TimeUnit.SECONDS.sleep(3);
            countDownLatch.countDown();
            System.out.println("ThreadOne 释放....");
        }
    }

    static class ThreadTwo extends Thread {
        @Override
        @SneakyThrows
        public void run() {
            TimeUnit.SECONDS.sleep(5);
            countDownLatch.countDown();
            System.out.println("ThreadTwo 释放....");
        }
    }
}
  • 阻塞所有子线程

/**
 * CountDownLatch quick start main线程countdown 子线程 await
 * 阻塞所有子线程,main线程中countdown计数为0之后,再释放所有阻塞的子线程,阻塞多个线程
 *
 * @author zdp
 * @date 2022-06-06 09:49
 */
public class CountDownLatchTestTwo {

    static CountDownLatch countDownLatch = new CountDownLatch(1);

    public static void main(String[] args) throws InterruptedException {
        ThreadOne one = new ThreadOne();
        ThreadTwo two = new ThreadTwo();
        one.start();
        two.start();
        System.out.println("main 线程阻塞....");
        TimeUnit.SECONDS.sleep(2);
        countDownLatch.countDown();
        System.out.println("main 线程释放....");
    }

    static class ThreadOne extends Thread {
        @Override
        @SneakyThrows
        public void run() {
            System.out.println("ThreadOne 阻塞....");
            countDownLatch.await();
            System.out.println("ThreadOne 释放....");
        }
    }

    static class ThreadTwo extends Thread {
        @Override
        @SneakyThrows
        public void run() {
            System.out.println("ThreadTwo 阻塞....");
            countDownLatch.await();
            System.out.println("ThreadTwo 释放....");
        }
    }
}

Cyclicbarrier

  • 不带回调

/**
 * CyclicBarrier quick start 可重复的栅栏
 * CyclicBarrier 就相当于CountDownLatch 的阻塞多个线程,当多个子线程都执行完都到达栅栏,然后一起释放所有子线程
 *
 * @author zdp
 * @date 2022-06-02 10:04
 */
public class CyclicBarrierTest {
    public static void main(String[] args) {
        //不带回调
        CyclicBarrier cyclicBarrier = new CyclicBarrier(4);

        for (int i = 0; i < 4; i++) {
            new Waiter(cyclicBarrier).start();
        }
    }

    static class Waiter extends Thread {

        private CyclicBarrier cyclicBarrier;

        public Waiter(CyclicBarrier cyclicBarrier){
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            try {
                //相当于 CountDownLatch 的countdown -1操作
                TimeUnit.SECONDS.sleep(2);
                System.out.println("子线程" + Thread.currentThread().getName() + "执行完毕,等待其他线程执行任务....");
                cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 带回调方法

/**
 * CyclicBarrier quick start 带回调的 CyclicBarrier
 * 所有子线程执行完,
 * @author zdp
 * @date 2022-06-06 10:38
 */
public class CyclicBarrierCallbackTest {

    public static void main(String[] args) {
        //带回调
        CyclicBarrier callBack = new CyclicBarrier(4, () -> System.out.println("其他线程任务执行完毕,执行回调任务...."));

        for (int i = 0; i < 4; i++) {
            new CyclicBarrierTest.Waiter(callBack).start();
        }
    }

    static class Waiter extends Thread {

        private CyclicBarrier cyclicBarrier;

        public Waiter(CyclicBarrier cyclicBarrier){
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            try {
                //相当于 CountDownLatch 的countdown -1操作
                TimeUnit.SECONDS.sleep(2);
                System.out.println("子线程" + Thread.currentThread().getName() + "执行完毕,等待其他线程执行任务....");
                cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

Semaphore

/**
 * Semaphore 相当于一个限制并发访问的容器,达到限制资源数量会阻塞,通过AQS共享锁实现
 *
 * Semaphore quick start
 *
 * @author zdp
 * @date 2022-06-02 10:03
 */
public class SemaphoreTest {
    public static void main(String[] args) {
        //停车场5个车位
        Semaphore semaphore = new Semaphore(5);
        //20辆车进停车场停车
        for (int i = 1; i <= 20; i++) {
            new Car(i, semaphore).start();
        }
    }

    static class Car extends Thread {

        /**
         * 车辆序号
         */
        private int serialNumber;
        /**
         * 停车场
         */
        private Semaphore semaphore;

        public Car(int serialNumber, Semaphore semaphore){
            this.serialNumber = serialNumber;
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                //抢占一个车位
                semaphore.acquire();
                System.out.println("第" + serialNumber + "辆车,进入停车场...");
                TimeUnit.SECONDS.sleep(1);
                System.out.println("第" + serialNumber + "辆车,离开停车场...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //释放一个车位
                semaphore.release();
            }
        }
    }
}

Exchanger

/**
 * Exchanger 基础使用
 *
 * Exchanger 用于线程之间数据的交换。它提供一个同步点,在这个同步点两个线程可以交换彼此的数据。这两个线程通过exchange方法交换数据,
 * 如果第一个线程先执行exchange方法,它会一直等待第二个线程也执行exchange,当两个线程都到达同步点时,这两个线程就可以交换数据,
 * 将本线程生产出来的数据传递给对方。因此使用Exchanger的重点是成对的线程使用exchange()方法,当有一对线程达到了同步点,就会进行交换数据。因此该工具类的线程对象是成对的
 *
 * public V exchange(V x);  用于交换,启动交换并等待另一个线程调用exchange
 *
 * public V exchange(V x, long timeout, TimeUnit unit); 用于交换,启动交换并等待另一个线程调用exchange,超过超时时间便停止等待
 *
 * Exchanger 必须是线程成对使用,如果不是成对使用将导致长时间阻塞
 * 
 * @author zdp
 * @date 2022-07-26 16:22
 */
@Slf4j
public class ExchangerExample {

    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();
        ExecutorService executor = Executors.newFixedThreadPool(10);
        executor.submit(() -> {
            try {
                log.info("线程【" + Thread.currentThread().getName() + "】开始执行...");
                // 让线程2先达到同步点
                TimeUnit.SECONDS.sleep(3);
                String resultOne = "Thread One Result....";
                log.info("线程【" + Thread.currentThread().getName() + "】到达同步点...准备交换的数据是: " + resultOne);
                String threadOneResult = exchanger.exchange(resultOne);
                log.info("线程【" + Thread.currentThread().getName() + "】获取的交换数据是{}", threadOneResult);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("线程【" + Thread.currentThread().getName() + "】运行结束");
        });

        executor.submit(() -> {
            String resultTwo = "Thread Two Result....";
            try {
                log.info("线程【" + Thread.currentThread().getName() + "】开始执行...");
                log.info("线程【" + Thread.currentThread().getName() + "】达到同步点...准备交换的数据是: " + resultTwo);
                String threadTwoResult = exchanger.exchange(resultTwo);
                log.info("线程【" + Thread.currentThread().getName() + "】获取的交换数据是{}", threadTwoResult);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("线程【" + Thread.currentThread().getName() + "】运行结束");
        });

        executor.submit(() -> {
            String resultThree = "Thread Three Result....";
            try {
                log.info("线程【" + Thread.currentThread().getName() + "】开始执行...");
                log.info("线程【" + Thread.currentThread().getName() + "】达到同步点...准备交换的数据是: " + resultThree);
                String threadThreeResult = exchanger.exchange(resultThree);
                log.info("线程【" + Thread.currentThread().getName() + "】获取的交换数据是{}", threadThreeResult);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("线程【" + Thread.currentThread().getName() + "】运行结束");
        });

        executor.submit(() -> {
            String resultFour = "Thread Four Result....";
            try {
                log.info("线程【" + Thread.currentThread().getName() + "】开始执行...");
                log.info("线程【" + Thread.currentThread().getName() + "】达到同步点...准备交换的数据是: " + resultFour);
                String threadFourResult = exchanger.exchange(resultFour);
                log.info("线程【" + Thread.currentThread().getName() + "】获取的交换数据是{}", threadFourResult);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("线程【" + Thread.currentThread().getName() + "】运行结束");
        });
        
        executor.shutdown();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值