并发工具CountDownLatch&CyclieBarrier&Semaphore

本文介绍了并发工具CountDownLatch、CyclicBarrier和Semaphore的使用。CountDownLatch用于等待多个线程完成任务,CyclicBarrier则允许一组线程等待至某个状态后再同时执行,两者在调用方式和应用场景上有区别。Semaphore作为计数信号量,用于管理有限的资源访问。
摘要由CSDN通过智能技术生成

CountDownLatch

CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器功能
eg:如有一个任务A,要等待其他n个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现,每当线程完成任务后,计数器值就会减1.当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
使用方法初始化的时候给定一个初始化的值
每个线程完成后调用countDown()方法,计数到达0,则释放所有等待
await()如果不是0,则使当前线程在锁存器倒计至零之前一直等待,除非线程被中断,等到0之后才唤醒主线程

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class FightQueryDemo {

    private static List<String> company= Arrays.asList("东方航空","南方航空","海南航空");
    private static List<String> fightList=new ArrayList<>();

    public static void main(String[] args) throws InterruptedException{
        String origin="BJ";
        String dest="SH";
        Thread[] threads=new Thread[company.size()];
        CountDownLatch latch=new CountDownLatch(company.size());

        for (int i = 0; i < threads.length; i++) {
            String name=company.get(i);
            threads[i]=new Thread(()->{
                System.out.printf("%s 查询从%s到%s的机票\n",name,origin,dest);
                //随机产生票数
                int val=new Random().nextInt(10);
                try {
                    TimeUnit.SECONDS.sleep(val);
                    fightList.add(name+"--"+val);
                    System.out.printf("%s公司查询成功!\n",name);
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            threads[i].start();
        }
        latch.await();
        System.out.println("==============查询结果如下:================");
        fightList.forEach(System.out::println);
    }
}
前半部分是串行 中间查询是并行 最后又回到主线程执行

CyclieBarrier

cyclieBarrier意思是回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier 可以被重用。我们暂且把这个状态叫做 barrier,当调用 await()方法之后,线程就处于 barrier了
基本原理:每个线程执行时,都会碰到一个屏障,直到所有线程执行结束,然后屏障才会打开,使所有线程继续往下执行。
在CyclicBarrier 的内部定义了一个 Lock 对象,每当一个线程调用 await方法时,将拦截的线程数加1,然后判断剩余拦截数是否为初始值 parties,如果不是,进入Lock对象的条件队列等待。如果是,执行barrierAction 对象的 Runnable 方法,然后将锁的条件队列中的所有线程放入锁等待队列中,这些线程会依次的获取锁、释放锁。
CycliBarrier的两个构造函数:CyclicBarrier(int parties)和 CyclicBarrier(int parties,Runnable barrierAction) 前者只需要声明拦截的线程数即可,后者需要定义一个等待所有线程到达屏障优先执行的 Runnable对象

import java.util.Random;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

public class RaceDemo {

    public static void main(String[] args) {
        CyclicBarrier barrier=new CyclicBarrier(8);
        Thread[] play=new Thread[8];
        for (int i = 0; i < 8; i++) {
            play[i]=new Thread(()->{
                try {
                    TimeUnit.SECONDS.sleep(new Random().nextInt(10));
                    System.out.println(Thread.currentThread().getName()+"准备好了");
                    barrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("选手"+Thread.currentThread().getName()+"起跑");
            },"play["+i+"]");
            play[i].start();
        }
    }
}

CountDownLatch 和 CyclicBarrier 区别

对于CountDownLatch 和 CyclicBarrier 两个类,都是多个线程要做完事情之后等待其他线程完成,全部线程完成之后再恢复运行。不同的是 CountDownLatch 类需要你自己调用 countDown()方法减少一个计数器,然后调用 await() 方法即可。而 CyclicBarrier 则直接调用 await()方法即可
CountDownLatch -1
CyclicBarrier +1
CountDownLatch 更倾向于多个线程合作的情况,等你所有东西准备好了,在自动执行。而CyclicBarrier 则是我们都在一个地方等你,大家到齐了,大家再一起执行

Semaphore

Semaphore 计数信号量,维护一个许可集,初始化默认是非公平锁并需要传入需要创建的许可数,也

  • 信号量可以使用的资源数量
  • 步骤
    • 请求资源 acquire ,获取许可
    • 使用资源 (业务处理)
    • 释放资源 release()
资源有限共享,如停车场 只有5个停车位
import com.sun.javafx.animation.TickCalculation;

import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class CarDemo {
    public static void main(String[] args) {
        //创建Semaphore
        Semaphore sp=new Semaphore(5);

        Thread[] car=new Thread[10];
        for (int i = 0; i < 10; i++) {
            car[i]=new Thread(()->{
                //请求许可
                try {
                    sp.acquire();
                    System.out.println(Thread.currentThread().getName()+"可以进停车场");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //使用资源
                try {
                    int val= new Random().nextInt(10);
                    TimeUnit.SECONDS.sleep(val);
                    System.out.println(Thread.currentThread().getName()+"停留了"+val+"秒");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //离开(释放资源)

                try {

                    sp.release();
                    System.out.println(Thread.currentThread().getName()+"离开停车场");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            },"car["+i+"]");
            car[i].start();
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值