【JUC并发】Java中的并发工具类

本文深入介绍了Java中的四个并发工具类:CountDownLatch、CyclicBarrier、Semaphore和Exchanger。包括它们的原理、使用方法及示例代码,帮助读者理解如何有效利用这些工具来控制多线程间的同步。

Java中的并发工具类

CountDownLatch(减法计数器,由一个同步队列实现)

概述

​ 通过构造方法传入的参数作为计数器,当调用countDown()方法时,计数器的数值就会减一,CountDownLatch的await()方法就会阻塞当前线程直到计数器变成0。如果某个线程解析的比较慢,我们可以使用**await(long time, TimeUtil unit)**这个方法等待特定的时间后,就不再阻塞当前线程。

初始化

public CountDownLatch(int count) {
    //count必须大于等于0
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}

/**
 *	通过一个静态内部类(同步队列)实现
 */
private static final class Sync extends AbstractQueuedSynchronizer {
    Sync(int count) {
        setState(count);
    }
}
private final Sync sync;

countDown()方法

public void countDown() {
    sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        //调用同步队列中的方法,共享式的释放同步状态
        doReleaseShared();
        return true;
    }
    return false;
}
protected boolean tryReleaseShared(int releases) {
    // Decrement count; signal when transition to zero
    for (;;) {
        //得到当前计数器的值
        int c = getState();
        if (c == 0)
            return false;
        //得到下一个计数器的值
        int nextc = c-1;
        //尝试将下一个计数器的值与第一个值交换
        if (compareAndSetState(c, nextc))
            return nextc == 0;
    }
}

await()方法

public void await() throws InterruptedException {
    //共享式的获取同步状态,如果当前线程未获取同步状态,就进入同步队列中等待,可中断。
    sync.acquireSharedInterruptibly(1);
}
/**
 *	计数器初始化
 */


/**
 *	countDown()方法,每次减一个。
 */
public void countDown() {
    sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}
protected boolean tryReleaseShared(int releases) {
    // Decrement count; signal when transition to zero
    for (;;) {
        //得到当前计数器的值
        int c = getState();
        if (c == 0)
            return false;
        //得到下一个计数器的值
        int nextc = c-1;
        //尝试将下一个计数器的值与第一个值交换
        if (compareAndSetState(c, nextc))
            return nextc == 0;
    }
}

使用

public class CountDownLatchTest {

    static CountDownLatch c = new CountDownLatch(4);

    public static void main(String[] args) throws InterruptedException {

        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(3);

                while (c.getCount() != 0){
                    c.countDown();
                    System.out.println(Thread.currentThread().getName()+":"+c.getCount());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        },"A").start();

        System.out.println("开始阻塞......");
        c.await();
        System.out.println("阻塞结束......");

    }
}


开始阻塞......
A:3
A:2
A:1
A:0
阻塞结束......

注意

CountDownLatch的参数必须大于等于0。CountDownLatch不可能重新初始化或者修改CountDownLatch对象的内部计数器的值。

CyclicBarrier(同步屏障,通过两个整型实现)

概述

​ 让一组线程到达一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障时,所有阻塞的线程才能运行。通过await()方法设置同步点

初始化

/**
 *@param1	parties	同步点数量
 *@param2	barrierAction	到达同步点优先运行的线程
 */
public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction;
}

await()方法

public int await() throws InterruptedException, BrokenBarrierException {
    try {
        return dowait(false, 0L);
    } catch (TimeoutException toe) {
        throw new Error(toe); // cannot happen
    }
}

private int dowait(boolean timed, long nanos)
    throws InterruptedException, BrokenBarrierException,
TimeoutException {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        /**
         *	......省略
         */

        //获取同步点-1后的数量
        int index = --count;
        //如果最后一个同步点已到达
        if (index == 0) {  // tripped
            boolean ranAction = false;
            try {
                //运行第二个参数所传入的线程
                final Runnable command = barrierCommand;
                if (command != null)
                    command.run();
                ranAction = true;
                //唤醒其他线程
                nextGeneration();
                return 0;
            } finally {
                if (!ranAction)
                    breakBarrier();
            }
        }

        // loop until tripped, broken, interrupted, or timed out
        for (;;) {
            /**
             *	......省略计时等待代码。
             */
        }
    } finally {
        lock.unlock();
    }
}

reset()方法,重置计数器

public void reset() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        //给count重新赋值
        breakBarrier();   // break the current generation
        //唤醒所有线程
        nextGeneration(); // start a new generation
    } finally {
        lock.unlock();
    }
}

使用

public class CyclicBarrierTest {

    static CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new C());

    public static void main(String[] args) {

        new Thread(()->{
            try {
                cyclicBarrier.await();
            }catch (Exception e){
                e.printStackTrace();
            }
            System.out.println(""+Thread.currentThread().getName());
        },"A").start();

        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(2);

                cyclicBarrier.await();
            }catch (Exception e){
                e.printStackTrace();
            }
            System.out.println(""+Thread.currentThread().getName());
        },"B").start();

    }

    static class C implements Runnable{

        @Override
        public void run() {
            System.out.println("C");
        }
    }
}

//打印结果
C
B
A

注意

CycliBarrier的计数器可以通过reset()方法重置,能处理更为复杂的业务场景。

Semaphore(信号量,同步队列实现)

概述

​ 用来控制同时访问特定致员的线程数量。当当前访问的线程达到最大访问量时,阻塞其他线程。

初始化

public Semaphore(int permits, boolean fair) {
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

acquire()方法

public void acquire() throws InterruptedException {
    //可中断的共享获取同步状态,如果未获取,进入等待队列
    sync.acquireSharedInterruptibly(1);
}

release

public void release() {
    //共享释放同步状态
    sync.releaseShared(1);
}

使用

public class SemaphoreTest {

    static Semaphore semaphore = new Semaphore(2);
    static ExecutorService service = Executors.newFixedThreadPool(6);

    public static void main(String[] args) {
        for (int i = 0; i < 6; i++) {
            service.execute(() -> {
                try {
                    semaphore.acquire();
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println("当前时间"+new Date().getSeconds()+ "(s)" +":save data");
                    semaphore.release();
                }catch (Exception e){
                    e.printStackTrace();
                }
            });
        }
        service.shutdown();
    }
}

//打印结果
当前时间8(s):save data
当前时间8(s):save data
当前时间9(s):save data
当前时间9(s):save data
当前时间10(s):save data
当前时间10(s):save data
Exchanger(交换者,通过ThreadLocal实现)

概述

​ 用于进行线程间的数据交换。它提供一个**同步点**,在这个同步点两个线程可以交换彼此的数据。线程可以通过exchange()方法到达同步点,第一个线程到达之后,会一直等待第二个线程到达,然后交换数据。

使用

public class ExchangerTest {

    static Exchanger<String> exchanger = new Exchanger<>();

    public static void main(String[] args) {

        new Thread(()->{
            String msg = "你好!很高兴见到你。";
            try {
                msg = exchanger.exchange(msg);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":"+msg);
        },"A").start();


        new Thread(()->{
            try {
                String s = exchanger.exchange("");
                System.out.println(Thread.currentThread().getName()+":"+s);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"B").start();
    }
}


//打印结果
A:
B:你好!很高兴见到你。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值