J.U.C的并发工具

CountDownLatch

就是一个计数器

  • await阻塞线程
  • countDown计数器减1,计数器为0时唤醒await线程
    在这里插入图片描述

让一个线程阻塞用法

public class CountDownExample {
    static CountDownLatch countDownLatch=new CountDownLatch(3);

    static class Thread1 extends Thread{
        @Override
        public void run(){
            System.out.println("1干完了");
            //表示我已经干完了
            countDownLatch.countDown();
        }
    }

    static class Thread2 extends Thread{
        @Override
        public void run(){
            System.out.println("2干完了");
            //表示我已经干完了
            countDownLatch.countDown();
        }
    }

    static class Thread3 extends Thread{
        @Override public void run(){
            System.out.println("3干完了");

            //表示我已经干完了
            countDownLatch.countDown();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //Thread.join()
        Thread1 t1 = new Thread1();
        t1.start();
        Thread2 t2 = new Thread2();
        t2.start();
        Thread3 t3 = new Thread3();
        t3.start();
        //阻塞main线程
        countDownLatch.await();
        //被唤醒后打印
        System.out.println("所有线程执行结束");
    }
}

在这里插入图片描述
类似于Thread.join,但还是有比较大的差别。

让多个线程阻塞用法

public class CountDownExample {

    static CountDownLatch countDownLatch=new CountDownLatch(1);

    static class Thread1 extends Thread{

        @Override
        public void run(){
            try {
                countDownLatch.await();
                System.out.println("主线程跑完了,1可以跑了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    static class Thread2 extends Thread{

        @Override
        public void run(){
            try {
                countDownLatch.await();
                System.out.println("主线程跑完了,2可以跑了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    static class Thread3 extends Thread{
        @Override
        public void run(){
            try {
                countDownLatch.await();
                System.out.println("主线程跑完了,3可以跑了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //相似于Thread.join
        Thread1 t1=new Thread1();
        t1.start();
        Thread2 t2=new Thread2();
        t2.start();
        Thread3 t3=new Thread3();
        t3.start();
        Thread.sleep(1000);
        System.out.println("睡眠晚了");
        countDownLatch.countDown();
    }
}

在这里插入图片描述

实际应用(检测数据库,缓存两个服务的状态)

检查类

public class ApplicationStartup {

    private static List<BaseHealthChecker> services;
    private static CountDownLatch countDownLatch=new CountDownLatch(2);

    static{
        services=new ArrayList<>();
        services.add(new CacheHealthChecker(countDownLatch));
        services.add(new DatabaseHealthChecker(countDownLatch));
    }

    private final static ApplicationStartup INSTANCE=new ApplicationStartup();

    private ApplicationStartup(){}

    public static ApplicationStartup getInstance(){
        return INSTANCE;
    }

    public static boolean checkExternalServices() throws InterruptedException {
        for(BaseHealthChecker bh:services){
            new Thread(bh).start(); //针对每个服务采用线程来执行
        }
        countDownLatch.await();
        return true;
    }
}
public abstract class BaseHealthChecker implements Runnable{

    private String serviceName; //服务名称

    private boolean serviceUp;

    public BaseHealthChecker(String serviceName) {
        this.serviceName = serviceName;
    }

    @Override
    public void run() {
        try {
            verifyService();
            serviceUp=true;
        }catch (Exception e){
            serviceUp=false;
        }finally {

        }
    }

    /**
     * 检查服务的健康情况
     */
    public abstract void verifyService() throws Exception;

    public String getServiceName() {
        return serviceName;
    }

    public boolean isServiceUp() {
        return serviceUp;
    }
}

数据库检查类

public class DatabaseHealthChecker extends BaseHealthChecker{
    private CountDownLatch countDownLatch;


    public DatabaseHealthChecker(CountDownLatch countDownLatch) {
        super("DatabaseHealthChecker");
        this.countDownLatch=countDownLatch;
    }

    @Override
    public void verifyService() throws Exception {
        System.out.println("Checking:"+this.getServiceName());
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            throw e;
        }
        countDownLatch.countDown();
        System.out.println(this.getServiceName()+" 健康状态正常");
    }

}

缓存检查类

public class CacheHealthChecker extends BaseHealthChecker{

    private CountDownLatch countDownLatch;

    public CacheHealthChecker(CountDownLatch countDownLatch) {
        super("CacheHealthChecker");
        this.countDownLatch=countDownLatch;
    }

    @Override
    public void verifyService() throws Exception {
        System.out.println("Checking:"+this.getServiceName());
        try {
            Thread.sleep(1000);
            // 如果检查失败,throw RuntimeException()
        } catch (Exception e) {
            throw e;
        }
        countDownLatch.countDown();
        System.out.println(this.getServiceName()+" 健康状态正常");
    }
}

启动类

public class StartupMain {
    public static void main(String[] args) {
        try {
            ApplicationStartup.checkExternalServices();
        } catch (InterruptedException e) {
            //有问题了.
        }
        System.out.println("服务启动成功");
    }
}

在这里插入图片描述
这样就变多线程了,不用顺序检查

思考底层原理

让多个线程阻塞其实就是共享锁的实现
即:可以允许多个线程同时抢占到锁,然后等到计数器归零的时候,同时唤醒.

  • state作为记录计数器.
  • countDown的时候,实际上就是 state–
  • 需要一个数据结构存储被阻塞的线程

再看源码
在这里插入图片描述

在这里插入图片描述
跟AQS果然关联起来了

再看await方法

public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
}


public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)//返回-1说明state!=0,可以抢占共享锁
            doAcquireSharedInterruptibly(arg);
}

protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;//state!=0返回-1,==0返回1
}

Semaphore

信号灯.
限流器,限制资源的访问,限制同时执行的线程数量
本质上: 抢占一个令牌,如果抢占到令牌,就通行, 否则,就阻塞!

  • acquire() 抢占一个令牌,可以传递参数,表示一次抢占多少个令牌
  • release() 释放一个令牌.

经典案例

public class SemaphoreExample {

    public static void main(String[] args) {
        //限制资源的并发数量.
        Semaphore semaphore=new Semaphore(10);
        for (int i = 0; i < 20; i++) {
            new Car(i,semaphore).start();
        }
    }
    static class Car extends  Thread{
        private int num;
        private Semaphore semaphore;

        public Car(int num, Semaphore semaphore) {
            this.num = num;
            this.semaphore = semaphore;
        }
        @Override
        public void run(){
            try {
                semaphore.acquire(); //获得一个令牌
                System.out.println("第 "+num+"俩车抢到一个车位");
                TimeUnit.SECONDS.sleep(2);
                System.out.println("第 "+num+"走喽~");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                semaphore.release(); //释放一个令牌
            }
        }
    }
}

CyclicBarrier

可重复的栅栏

public class CyclicBarrierExample {

    public static void main(String[] args) {
        int n=4;
        //参数4代表参与线程有4个,后面就是这4个线程都执行完了,即调用wait减到0了,再执行这个后续的东西
        CyclicBarrier barrier=new CyclicBarrier(4,()->{
            System.out.println("所有线程都写入完成,继续处理其他任务");
        });  // 4
        for (int i = 0; i < n; i++) {
            new Writer(barrier).start();
        }
    }
    static class Writer extends Thread{
        private CyclicBarrier cyclicBarrier;
        public Writer(CyclicBarrier barrier){
            this.cyclicBarrier=barrier;
        }
        @Override
        public void run(){
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+"写入数据完毕,等待其他线程");
                cyclicBarrier.await();  //-1的动作
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }

        }
    }
}

在这里插入图片描述

Exchanger

不常用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值