JAVA多线程同步计数器

一、 CountDownLatch

概念

CountDownLatch是一个同步工具类,它允许一个或多个线程等待其他线程一系列操作的完成

CountDownLatch初始化必须给定一个int类型参数count,来表示事件总数。

CountDownLatch提供的主要方法:

方法 说明
await() 使当前线程进入同步队列进行等待,直到latch的值被减到0或者当前线程被中断,当前线程就会被唤醒
await(long timeout, TimeUnit unit) 带超时时间的await()
countDown() 使latch的值减1),如果减到了0,则会唤醒所有等待在这个latch上的线程
getCount() 获得latch的数值

使用场景:

  1. 高并发并行执行(让多个线程等待)
  2. 异步执行后回到业务主线程(让一个线程等待)(推荐)
1. 高并发并行执行
public static void main(String[] args) throws InterruptedException {
   CountDownLatch countDownLatch = new CountDownLatch(1);
    for (int i = 1; i <= 3; i++) {
        new Thread(() -> {
            System.out.println("短跑运动员" + Thread.currentThread().getName() + "准备好了");
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("短跑运动员" + Thread.currentThread().getName() + "开始奔跑");
        }, String.valueOf(i)).start();
    }
    System.out.println("短跑运动员们进场");
    Thread.sleep(1000); //睡眠1秒,保证所有子线程创建完毕都进入run方法,执行await()方法
    countDownLatch.countDown();
    System.out.println("各就位");
    System.out.println("预备");
    System.out.println("鸣枪");
}
短跑运动员们进场
短跑运动员1准备好了
短跑运动员2准备好了
短跑运动员3准备好了
各就位
预备
鸣枪
短跑运动员2开始奔跑
短跑运动员3开始奔跑
短跑运动员1开始奔跑
2. 异步执行后回到业务主线程(推荐)
public static void main(String[] args) throws InterruptedException {
    CountDownLatch countDownLatch = new CountDownLatch(3);
    System.out.println("业务开始分发各个子流程进行处理");
    for (int i = 1; i <= 3; i++) {
        new Thread(() -> {
            System.out.println("业务分支流程" + Thread.currentThread().getName() + "开始处理");
            countDownLatch.countDown();
            System.out.println("业务分支流程" + Thread.currentThread().getName() + "处理完成");
        }, String.valueOf(i)).start();
    }
    countDownLatch.await();
    System.out.println("业务处理结果汇总进行后续处理");
}
业务开始分发各个子流程进行处理
业务分支流程1开始处理
业务分支流程2开始处理
业务分支流程2处理完成
业务分支流程1处理完成
业务分支流程3开始处理
业务分支流程3处理完成
业务处理结果汇总进行后续处理

二、 CyclicBarrier

概念

CyclicBarrier同步工具类,循环屏障,通过它可以让一组线程等待至某个屏障(同步点)之后再全部同步执行。所有线程被释放之后,CyclicBarrierr可以被重新利用

CountDownLatch初始化必须给定一个int类型参数parties,来表示参与屏障等待的线程的总个数。

public static void main(String[] args) {
        CyclicBarrier cb = new CyclicBarrier(3, ()->{
            System.out.println("匹配完成");
        });
        System.out.println("游戏开始匹配……");
        for (int i = 0; i < 7; i++) {
            new Thread(() -> {
                boolean target = true;
                System.out.println("玩家" + Thread.currentThread().getName() + "开始匹配");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    cb.await(3, TimeUnit.SECONDS);
                } catch (Exception e) {
                    target = false;
                    System.out.println("玩家" + Thread.currentThread().getName() + "匹配失败,请重新匹配");
                } finally {
                    if (target) {
                        System.out.println("玩家" + Thread.currentThread().getName() + "匹配成功,开始游戏");
                    }  
                }
            }, String.valueOf(i)).start();
        }
    }
游戏开始匹配……
玩家0开始匹配
玩家1开始匹配
玩家2开始匹配
玩家3开始匹配
玩家4开始匹配
玩家5开始匹配
玩家6开始匹配
匹配完成
玩家4匹配成功,开始游戏
玩家5匹配成功,开始游戏
玩家6匹配成功,开始游戏
匹配完成
玩家1匹配成功,开始游戏
玩家3匹配成功,开始游戏
玩家2匹配成功,开始游戏
玩家0匹配失败,请重新匹配

三、 Semaphore

概念

Semaphore信号量,多线程并发控制工具,可以控制同时访问共享资源的线程个数

CountDownLatch初始化必须给定一个int类型参数permits,来表示可以控制同时访问共享资源的线程个数。
CountDownLatch提供的主要方法:

方法 说明
acquire() 获取一个资源许可,如果没有获取到则阻塞
release() 释放一个资源许可
availablePermits() 剩余可获取许可数量
public static void main(String[] args) {
    Semaphore semaphore = new Semaphore(3);
    for (int i = 0; i < 5; i++) {
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + "来到停车场");
                if (semaphore.availablePermits() == 0) {
                    System.out.println("车位不足,请耐心等待");
                }
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName() + "成功进入停车场并停好车");
                Thread.sleep(new Random().nextInt(2000));
                System.out.println(Thread.currentThread().getName() + "驶出停车场");
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, i + "号车").start();
    }
}
0号车来到停车场
0号车成功进入停车场并停好车
1号车来到停车场
1号车成功进入停车场并停好车
2号车来到停车场
2号车成功进入停车场并停好车
4号车来到停车场
车位不足,请耐心等待
3号车来到停车场
车位不足,请耐心等待
1号车驶出停车场
4号车成功进入停车场并停好车
2号车驶出停车场
3号车成功进入停车场并停好车
0号车驶出停车场
3号车驶出停车场
4号车驶出停车场

你可能感兴趣的:(JAVA学习,并发/多线程,java)