juc包下的四大工具类

本文详细介绍了Java并发编程中juc包的四大工具类:CountDownLatch、CyclicBarrier、Exchanger和Semaphore。CountDownLatch用于线程等待其他线程完成任务;CyclicBarrier可以重复使用,允许线程在特定条件达成后继续执行;Exchanger用于两个线程间的数据交换;Semaphore则作为信号量,限制同时访问特定资源的线程数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

juc包下的四大工具类

CountDownLatch

CyclicBarrier

Exchange

Semaphore

1.CountDownLatch–闭锁

作用为:解决一个线程需等待其他线程完成任务后再次恢复执行的情景。

注意:每个CountDownLatch对象的计数器在减为0时不可恢复原值。

CountDownLatch类常用方法:

//调用await()方法的线程阻塞直到其他线程完成任务才可恢复执行
1.public void await() throws InterruptedException {}
//await()方法的重载方法,作用为等待timeout时间后无论其他线程是否完成任务均恢复执行
2.public boolean await(long timeout, TimeUnit unit) throws InterruptedException {}
//CountDownLatch类唯一的构造方法,count为需要等待完成任务线程数量
3.public CountDownLatch(int count) {}
//该方法为兵法执行任务的线程调用,调用countDown方法相当于已执行完任务,count--,直到count=0时最初调用await()方法的阻塞线程才可恢复执行
4.public void countDown() {}

假想一个这样的场景:运动场上,裁判一声哨响,运动员起跑,裁判开始计时,等待最后一位运动员到达终点时裁判才可按下计时器,结束比赛。那么也就是说裁判要等到所有运动员都到达终点后才可按下计时器。那这个场景我们要怎么实现呢?使用之前多线程部分的知识,我们很容易就能想到join()方法,假想裁判是主线程,运动员均是子线程,使用join()方法就需要在所有子线程在主线程中调用join()方法,但线程在调用join()方法的先后顺序上也可能影响运行结果。

针对以上场景,我们可用CountDownLatch完美解决:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

class CountDownLatchTest implements Runnable{
    private CountDownLatch countDownLatch;
    public CountDownLatchTest(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"到达终点");
        countDownLatch.countDown();
    }
}
public class ThreadTest{
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch=new CountDownLatch(3);
        System.out.println("比赛开始...");
        new Thread(new CountDownLatchTest(countDownLatch),"运动员A").start();
        TimeUnit.SECONDS.sleep(2);
        new Thread(new CountDownLatchTest(countDownLatch),"运动员B").start();
        TimeUnit.SECONDS.sleep(2);
        new Thread(new CountDownLatchTest(countDownLatch),"运动员C").start();
        countDownLatch.await();
        System.out.println("所有运动员均到达终点,比赛结束!");
    }
}

/*
比赛开始...
运动员A到达终点
运动员B到达终点
运动员C到达终点
所有运动员均到达终点,比赛结束!
*/

CountDownLatch图示:

在这里插入图片描述

2.CyclicBarrier–循环栅栏
注意:每个CyclicBarrier对象可重复使用。

CyclicBarrier常用方法:

//parties为需阻塞子线程个数
1.public CyclicBarrier(int parties) {}
//parties为需阻塞子线程个数,barrierAction为等所有线程到达同步点后,随机唤醒一个线程执行barrierAction任务,之后再全部线程恢复执行
2.public CyclicBarrier(int parties, Runnable barrierAction) {}
//子线程调用await()方法阻塞当前线程,CyclicBarrier计数器减一,直到减为0后恢复执行
3.public int await() throws InterruptedException, BrokenBarrierException {}

假想这样场景:有一本书,三个人分模块同时书写,假设A先写完,此时书不可能直接出版,必须等到剩余两人都写完才可以出版。下面用代码实现此场景:

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

class CycliBarrierTest implements Runnable{
    private CyclicBarrier cyclicBarrier;

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

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"已到达栅栏");
        try {
            cyclicBarrier.await();
            System.out.println(Thread.currentThread().getName()+"已完成任务");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}
public class ThreadTest{
    public static void main(String[] args) throws InterruptedException {
        CyclicBarrier cyclicBarrier=new CyclicBarrier(3);
        for(int i=0;i<3;i++){
            new Thread(new CycliBarrierTest(cyclicBarrier),"线程"+(i+1)).start();
            TimeUnit.SECONDS.sleep(2);
        }
    }
}
/**
线程1已到达栅栏
线程2已到达栅栏
线程3已到达栅栏
线程3已完成任务
线程1已完成任务
线程2已完成任务
**/

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

class CycliBarrierTest implements Runnable{
    private CyclicBarrier cyclicBarrier;

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

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"已到达栅栏");
        try {
            cyclicBarrier.await();
            System.out.println(Thread.currentThread().getName()+"已完成任务");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}
public class ThreadTest{
    public static void main(String[] args) throws InterruptedException {
        CyclicBarrier cyclicBarrier=new CyclicBarrier(3, new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"执行barrierAction任务");
            }
        });
        for(int i=0;i<3;i++){
            new Thread(new CycliBarrierTest(cyclicBarrier),"线程"+(i+1)).start();
            TimeUnit.SECONDS.sleep(2);
        }
    }
}
/**
线程1已到达栅栏
线程2已到达栅栏
线程3已到达栅栏
线程3执行barrierAction任务
线程1已完成任务
线程2已完成任务
线程3已完成任务
**/

CyclicBarrier图示:

在这里插入图片描述

3.Exchanger—线程数据交换器
应用场景:用于两个线程交换数据(不能用于多个)

常用方法:

public V exchange(V x) throws InterruptedException {}//调用exchange()方法会阻塞当前线程,必须等到另外一个线程时才可进行数据交换

Exchanger简单实现:

import java.util.concurrent.Exchanger;

public class ThreadTest{
    public static void main(String[] args) {
        Exchanger<String> exchanger=new Exchanger<>();
        Thread girl=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String str=exchanger.exchange("我喜欢你!");
                    System.out.println("女孩说:"+str);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        girl.start();
        Thread boy=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String str=exchanger.exchange("我也是!");
                    System.out.println("男孩说:"+str);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        boy.start();
    }
}
/**
男孩说:我喜欢你!
女孩说:我也是!
**/

Exchange图示:

在这里插入图片描述

4.Semaphore—信号量

常用方法:

//调用acquire()方法默认为申请一个信号量
1.public void acquire() throws InterruptedException {}
//permits为申请信号量数
2.public void acquire(int permits) throws InterruptedException {}
//默认释放一个信号量
3.public void release() {}
//释放permits个信号量
4.public void release(int permits) {}

假想一个这样的场景:一个工厂有8个工人5台机器,每台机器最多只能一个人进行操作,因此最多5人工作。

以下为Semaphore实现以上情景:

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

class SemaphoreTest implements Runnable{
    private Semaphore semaphore;
    private Integer num;

    public SemaphoreTest(Semaphore semaphore, Integer num) {
        this.semaphore = semaphore;
        this.num = num;
    }

    @Override
    public void run() {
        try {
            semaphore.acquire();
            System.out.println("工人"+this.num+"占用一台设备");
            TimeUnit.SECONDS.sleep(2);
            System.out.println("工人"+this.num+"释放本设备");
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class ThreadTest{
    public static void main(String[] args) {
        Semaphore semaphore=new Semaphore(5);
        //8个工人,5台机器
        for(int i=0;i<8;i++){
            new Thread(new SemaphoreTest(semaphore,i+1)).start();
        }
    }
}

/**
工人1占用一台设备
工人2占用一台设备
工人3占用一台设备
工人4占用一台设备
工人5占用一台设备
工人2释放本设备
工人4释放本设备
工人5释放本设备
工人3释放本设备
工人8占用一台设备
工人1释放本设备
工人7占用一台设备
工人6占用一台设备
工人8释放本设备
工人7释放本设备
工人6释放本设备
**/


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

class SemaphoreTest implements Runnable{
    private Semaphore semaphore;
    private Integer num;

    public SemaphoreTest(Semaphore semaphore, Integer num) {
        this.semaphore = semaphore;
        this.num = num;
    }

    @Override
    public void run() {
        try {
            semaphore.acquire(2);
            System.out.println("工人"+this.num+"占用一台设备");
            TimeUnit.SECONDS.sleep(2);
            System.out.println("工人"+this.num+"释放本设备");
            semaphore.release(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class ThreadTest{
    public static void main(String[] args) {
        Semaphore semaphore=new Semaphore(5);
        //8个工人,5台机器
        for(int i=0;i<8;i++){
            new Thread(new SemaphoreTest(semaphore,i+1)).start();
        }
    }
}
/**
工人2占用一台设备
工人3占用一台设备
工人2释放本设备
工人4占用一台设备
工人3释放本设备
工人1占用一台设备
工人1释放本设备
工人4释放本设备
工人5占用一台设备
工人6占用一台设备
工人6释放本设备
工人5释放本设备
工人7占用一台设备
工人8占用一台设备
工人8释放本设备
工人7释放本设备
**/

Semaphore图示:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值