java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java CountDownLatch

java使用CountDownLatch实现多线程协作

作者:FirstMrRight

在多线程编程中,经常需要实现一种机制来协调多个线程的执行,以确保某些操作在所有线程完成后再进行,CountDownLatch 就是 Java 并发包中提供的一种同步工具,下面我们就来看看如何使用CountDownLatch实现多线程协作吧

前言

在多线程编程中,经常需要实现一种机制来协调多个线程的执行,以确保某些操作在所有线程完成后再进行。CountDownLatch 就是 Java 并发包中提供的一种同步工具,它能够让一个或多个线程等待其他线程完成操作。

了解 CountDownLatch

概括

CountDownLatch 是Java 1.5版本推出的一个同步辅助类,在构造时需要指定一个计数值,该计数值表示需要等待的事件数量。每当一个事件完成时,计数值就会减一,当计数值减至零时,等待的线程就会被唤醒继续执行。

CountDownLatch 的应用场景

CountDownLatch 可以被广泛应用于各种多线程协作的场景,例如:

使用案例

让我们通过一个示例代码来理解 CountDownLatch 的使用。假设有一个任务需要被分配给多个子线程来完成,并且主线程需要等待所有子线程执行完毕后才能继续执行。

//任务分割的线程数
private static final int THREAD_TOTAL = 10;

//子线程执行的超时时间
private static final int countDownLatchTimeout = 5;

public static void main(String[] args) {
    //创建CountDownLatch并设置计数值,该count值可以根据线程数的需要设置
    CountDownLatch countDownLatch = new CountDownLatch(THREAD_TOTAL);

    //创建线程池,开启、创建异步线程执行任务
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    for (int i = 0; i < THREAD_TOTAL; i++) {
        cachedThreadPool.execute(() -> {
            try {
                Thread.sleep(5000);
                System.out.println(Thread.currentThread().getName() + " do something!");
            } catch (Exception e) {
                System.out.println("Exception: do something exception");
            } finally {
                //该线程执行完毕-1
                countDownLatch.countDown();
            }
        });
    }

    //回到主线程中
    System.out.println("Back main thread do something");
    try {
        //主线程等待线程池中完成(子线程执行超时时间)
        boolean await = countDownLatch.await(countDownLatchTimeout, TimeUnit.MINUTES);
        System.out.println(await);
    } catch (InterruptedException e) {
        System.out.println("Exception: await interrupted exception");
    } finally {
        System.out.println("countDownLatch: " + countDownLatch);
    }
    System.out.println("main thread do something-2");
}

CountDownLatch 的优缺点分析

优点

缺点

如果您学有余力或手头没有着急的需求,请继续往下看,让我们简单从源码层面分析下CountDownLatch的实现。

从源码层面分析CountDownLatch的实现

实现

我截取了CountDownLatch内部关键实现逻辑来分析其实现原理:

CountDownLatch的功能主要通过内部类Sync实现,在内部类中,Sync继承自AbstractQueuedSynchronizer来实现同步操作,AbstractQueuedSynchronizer提供了同步器实现的基础框架,通过该类,开发者可以相对容易地实现自定义的同步器,例如独占锁、共享锁、信号量等。

/**
 * Synchronization control For CountDownLatch.
 * Uses AQS state to represent count.
 */
private static final class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 4982264981922014374L;

    Sync(int count) {
        setState(count);
    }

    int getCount() {
        return getState();
    }

    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }

    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;
        }
    }
}

private final Sync sync;


public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}


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

tryReleaseShared

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;
    }
}

tryReleaseShared 方法尝试释放共享资源,首先通过一个无限循环不断尝试,在循环中获取当前状态值,如果状态值已经为0,则直接返回false;否则将状态值减1,并尝试原子性地设置状态值,如果设置成功,则返回是否状态值变为0,否则继续循环。

总的来说,这段代码实现了一个简单的 CountDownLatch 功能,通过 tryAcquireShared 方法尝试获取共享资源,通过 tryReleaseShared 方法尝试释放共享资源。当共享资源的状态值为0时,表示所有等待的线程都已被释放。

扩展

CompletableFuture简述

在JDK 1.8后,java.util.concurrent包提供了CompletableFuture类用于支持异步编程和异步任务的处理,相较于CountDownLatch,它提供了更丰富的API,就个人而言,我更喜欢CompletableFuture,因为它扩展性强,更适合JDK 8提供的函数式编程特性,代码更加优雅。

CompletableFuture 的优缺点

优点

缺点

总结

CountDownLatch 和 CompletableFuture 都是 Java 中用于多线程协作的工具,它们各自适用于不同的场景。CountDownLatch 更适合简单的多线程协作,而 CompletableFuture 则更适合复杂的异步编程场景。在实际应用中,我们可以根据具体的需求选择合适的工具来实现多线程协作和异步编程,以达到更好的开发效率和代码质量。

以上就是java使用CountDownLatch实现多线程协作的详细内容,更多关于java CountDownLatch的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文