zoukankan      html  css  js  c++  java
  • 并发编程(十五):Java并发工具类

    目录


    学习资料

    《Java并发编程的艺术》第8章


    1.CountDownLatch

    CountDownLatch允许一个或多个线程等待其他线程完成操作

    thread.join()可让当前线程等待thread执行完毕再执行,原理是不停检查join的线程是否存活,如果thread线程存活则让当前线程永远等待

    CountDownLatch可以实现join的功能且比join的功能更强大

    @Test
    public void test01() throws InterruptedException {
        CountDownLatch count=new CountDownLatch(2); //设置计数器为2
        
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(1);
                count.countDown();	//计数器-1
                System.out.println(2);
                count.countDown();	//计数器再-1
            }
        }).start();
        
        count.await();	//计数器不为0,当前线程会一直等待
        System.out.println(3);
    }
    
    • 调用countDown()方法时,计数器会减一,CountDownLatch的await()方法会阻塞当前线程(调用线程)直到计数器变为0
    • 可以在多个线程调用countDown(),只需要将CountDownLatch引用传递给其他线程即可
    • 计数器无法重置
    • 可以使用await(long time,TimeUnit unit)指定一个超时时间

    2.同步屏障CyclicBarrier

    2.1 简介

    CyclicBarrier,可循环使用的屏障,让一组线程到达一个屏障时(同步点)被阻塞,直到最后一个线程到达屏障时,所有被屏障拦截的线程才会继续运行

    有两个常用构造方法:

    • CyclicBarrier(int parties):表示拦截parties个线程之后才会"开门"
    • CyclicBarrier(int parties,Runnable barrierAction):在拦截之前调用barrierAction

    示例代码:(用第二个构造函数)

    //CyclicBarrier
    @Test
    public void test02() throws BrokenBarrierException, InterruptedException {
    
        //数量改为3永远不执行,因为没有第三个线程等待
        CyclicBarrier c=new CyclicBarrier(2, new Runnable() {
            @Override
            public void run() {
                //barrierAction
                System.out.println("先执行");
            }
        });
        
        //第一个线程
        new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                c.await();  //第一个阻塞
                System.out.println("第一个线程:thread");
            }
        }).start();
        
        c.await();  //第二个阻塞,开门
        System.out.println("第二个线程:main");
    }
    

    2.2 应用场景

    CyclicBarrier可用于多线程计算,最后合并每个线程的计算结果

    2.3 CyclicBarrier和CountDownLatch的区别

    CountDownLatch的计数器只能使用一次,CyclicBarrier计数器可以使用reset()方法重置,如果出错可以重置并重新执行线程

    CyclicBarrier的其他有用方法:

    • getNumberWaiting():获取阻塞的线程数量
    • isBroken():了解阻塞线程是否被中断过(可在异常中获取)

    3.Semaphore

    Semaphore(信号量),用来控制访问特定资源的线程数量,通过协调各个线程,以保证合理的使用公共资源

    3.1 应用场景

    Semaphore可用于做流量控制,特别是公用资源有限的应用场景,比如数据库连接

    如读取文件线程池启动了30个线程,然后保存数据库,数据库连接只有10个,线程不能超过10个,可以用Semaphore来限流:

    @Test
    public void test03(){
        ExecutorService threadpool= Executors.newFixedThreadPool(30);
        Semaphore s=new Semaphore(10);  //限流
        
        //循环30次
        for(int i=0;i<30;i++){
            threadpool.execute(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    s.acquire();    //获取许可证
                    System.out.println("连接数据库"); //同时只能10个连接,最终会打印出30个
                    s.release();    //使用完之后,归还许可证
                }
            });
        }
        
        threadpool.shutdown();
    }
    

    3.2 常用方法

    • acquire():获取许可证
    • release():归还许可证
    • avalilablePermits():返回此信号量中当前可用许可证数
    • getQueueLength():返回正在等待获取许可证的线程数
    • hasQueuedThreads():是否有线程正在等待获取许可证
    • reducePermits(int reduction):减少reduction个许可证
    • Collection getQueuedThreads():返回等待获取许可证的线程集合

    4.Exchanger

    Exchanger<E>是一个用于线程间协作的工具类。用于进行线程间数据交换

    第一个线程执行exchange(msg1)方法,会一直等待第二个线程也执行exchange(msg2)方法,当两个线程到大同步点时,两个线程就可以交换数据(msg1给第二个线程,msg2给第一个线程)

    示例代码:

    Exchanger<String> exgr=new Exchanger<String>();
    ...
    //第一个线程内
    String bStr=exgr.exchange("msg1");	//a传送数据给b线程,接收b线程的数据
    ...
    //第二个线程内
    String aStr=exgr.exchange("msg2");	//数据传给a线程,接收a线程数据
    ...
    

    可以使用exchange(V x,long timeout,TimeUnit unit)设置最大等待时长


  • 相关阅读:
    学习Python第三天
    学习Python第二天
    学习Python第一天
    centos7 系统优化
    crond计划任务
    day2
    day1
    A.浏览器访问 kube-apiserver 安全端口
    12.清理集群
    11.部署 harbor 私有仓库
  • 原文地址:https://www.cnblogs.com/kenshine/p/14520624.html
Copyright © 2011-2022 走看看