java并发编程JUC CountDownLatch线程同步

CountDownLatch 是一个线程同步工具,用于让特定的线程等待其他线程完成操作后再继续执行。当某个线程需要等待,直到一个或多个其他线程完成操作后,它们才能继续执行时,就可以使用 CountDownLatch。

1. CountDownLatch 的基本使用

1.1 原理和基本用法

CountDownLatch 的原理是,一个线程等待其他线程完成某些操作之后再执行。初始化 CountDownLatch 时需要指定“计数器”的初始值,即需要等待的线程数量。当有线程完成一个操作时,计数器的值减一。当计数器的值为0时,等待线程就可以继续执行。具体代码如下所示:

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        int count = 5;
        CountDownLatch countDownLatch = new CountDownLatch(count);
        for (int i = 0; i < count; i++) {
            Thread thread = new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " 执行完成");
                // 计数器减一
                countDownLatch.countDown();
            });
            thread.start();
        }
        System.out.println("等待5个线程执行完成...");
        // 主线程等待计数器归零
        countDownLatch.await();
        System.out.println("5个线程执行完成,主线程继续执行。");
    }
}

以上代码中,我们创建了一个 CountDownLatch 对象,初始计数器的值为5。然后创建5个线程,每个线程执行完成后调用 countDownLatch.countDown() 方法,将计数器减一。主线程调用 countDownLatch.await() 方法等待计数器的值归零。当计数器的值为0时,主线程会继续执行。

1.2 示例说明

我们来看一个实际的例子,假设有一个任务需要将一个文件读入内存、进行处理、然后存储到数据库。我们使用三个线程完成这个任务,一个线程读取文件,一个线程进行处理,一个线程将处理结果存储到数据库。

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.concurrent.CountDownLatch;

public class Task {
    private CountDownLatch countDownLatch = new CountDownLatch(2);
    private File file;

    public Task(File file) {
        this.file = file;
    }

    public void start() throws InterruptedException {
        Thread readThread = new Thread(() -> {
            try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    // do something
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                countDownLatch.countDown();
            }
        });
        readThread.start();
        Thread processThread = new Thread(() -> {
            // do something
            countDownLatch.countDown();
        });
        processThread.start();
        countDownLatch.await();
        Thread storeThread = new Thread(() -> {
            // do something
        });
        storeThread.start();
    }
}

在以上示例中,我们首先创建了一个 countDownLatch 对象(初始值为2),然后创建了两个线程,一个线程读取文件,一个线程进行处理。在这两个线程中,都需要等读取和处理完成后才能继续执行。使用 countDownLatch.countDown() 方法将计数器减一。主线程调用 countDownLatch.await() 等待计数器的值归零,然后再创建一个线程用于将处理结果存储到数据库。

2. CountDownLatch 的进阶使用

2.1 CountDownLatch 和线程池的结合使用

当我们使用线程池时,可能需要等待一些线程执行完毕后再执行一些操作。我们可以通过 CountDownLatch 来实现。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {
    public static void main(String[] args) throws InterruptedException {
        int count = 5;
        CountDownLatch countDownLatch = new CountDownLatch(count);
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for (int i = 0; i < count; i++) {
            executorService.execute(() -> {
                System.out.println(Thread.currentThread().getName() + " 执行完成");
                // 计数器减一
                countDownLatch.countDown();
            });
        }
        System.out.println("等待5个线程执行完成...");
        // 主线程等待计数器归零
        countDownLatch.await();
        System.out.println("5个线程执行完成,主线程继续执行。");
        executorService.shutdown();
    }
}

以上代码中,我们使用了线程池来执行任务,但是我们还需要等待所有线程执行完成。在每个线程执行完成之后,我们调用了 countDownLatch.countDown() 方法,将计数器减一。主线程调用 countDownLatch.await() 方法等待计数器的值归零。当计数器的值为0时,主线程继续执行。

2.2 CountDownLatch 和 Semaphore 的结合使用

Semaphore 是另一种线程同步工具,它也是用于控制多个线程对共享资源的访问。CountDownLatch 和 Semaphore 有很多相似之处,例如都可以用来控制线程的执行顺序。下面我们来看一下 CountDownLatch 和 Semaphore 的结合使用。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    public static void main(String[] args) throws InterruptedException {
        int threadCount = 5;
        Semaphore semaphore = new Semaphore(3);
        CountDownLatch countDownLatch = new CountDownLatch(threadCount);
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
        for (int i = 0; i < threadCount; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + " 执行完成");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();
                    countDownLatch.countDown();
                }
            });
        }
        System.out.println("已启动 " + threadCount + " 个线程,准备执行任务...");
        //主线程阻塞等待子线程执行完毕
        countDownLatch.await();
        System.out.println("所有线程执行完毕");
        executorService.shutdown();
    }
}

在以上示例中,我们创建了一个 Semaphore(初始值为3),然后使用线程池启动了5个线程。每个线程执行时均会尝试获取 Semaphore 的许可(即执行 semaphore.acquire()),如果 Semaphore 的许可数量不足,则线程会阻塞等待,直到获取到许可为止。当每个线程执行完成后会释放 Semaphore 的许可(即执行 semaphore.release())。主线程使用 CountDownLatch 等待所有线程执行完成,然后关闭线程池并退出。

总结

CountDownLatch 是 Java 中常用的线程同步工具,可以实现主线程等待多个线程执行完成后再继续执行的功能。在实际的开发中,CountDownLatch 常常和其他线程同步工具一起使用,例如和 Semaphore 结合使用可以控制多个线程对共享资源的访问。我们需要根据具体的业务需求来灵活使用不同的线程同步工具,才能更好地提高程序的并发性和性能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java并发编程JUC CountDownLatch线程同步 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月18日

相关文章

  • 浅谈Java中格式化输出

    Java中格式化输出是指通过特定的语法结构控制输出内容的方式,其使用起来非常灵活方便。下面是Java中格式化输出的一些基本知识和使用技巧。 格式化输出的基础知识 要使用Java中的格式化输出,需要了解以下基础知识: 语法结构 Java中格式化输出的语法结构为: System.out.printf(format, args); 其中,format是格式化字符串…

    Java 2023年5月26日
    00
  • Java基础教程之整数运算

    Java基础教程之整数运算攻略 Java是一种强类型语言,其中包含了整数类型及其运算操作。本文将详细讲解Java基础教程中的整数运算,包括基本概念、运算规则和示例说明。 基本概念 Java中的整数类型主要有四种:byte、short、int和long,对应的存储空间分别为1、2、4和8个字节。整数运算包括加、减、乘、除和取模等操作。 运算规则 Java中的整…

    Java 2023年5月26日
    00
  • js简单的分页器插件代码实例

    下面是关于“js简单的分页器插件代码实例”的完整攻略: 1. 什么是分页器 分页器是一种常见的网页分页功能,在信息展示较多的网页中特别常见,例如商品列表、新闻列表、书籍列表等。通俗的讲,分页器就是把一系列信息按一定的规则分成若干页,然后在页面上生成一个标准的页码导航,方便用户快速地切换页面。 2. 如何实现一个简单的分页器 下面介绍一种简单的前端JS分页器实…

    Java 2023年6月16日
    00
  • 用Java实现24点游戏

    用Java实现24点游戏攻略 游戏规则 24点游戏是一种比较常见的撕牌游戏,游戏过程如下: 取出4张扑克牌,其中可能包含1-10、J、Q、K四种牌面; 对玩家来说,可以自由任意(+-*/)组合这4张扑克牌,使其结果为24即可; 玩家须进行计算,并在30秒内作出答案,如果时间到了仍没有答案则选手视为失败。 游戏实现思路 为实现24点游戏,我们可以通过Java实…

    Java 2023年5月19日
    00
  • 详解在spring中使用JdbcTemplate操作数据库的几种方式

    下面是“详解在spring中使用JdbcTemplate操作数据库的几种方式”的完整攻略。 1. 前言 在Spring开发中,使用JdbcTemplate操作数据库是常见的一种方式,可以方便地完成对数据库的CRUD操作。JdbcTemplate是Spring对JDBC API的封装,使得对数据库的操作更加简单、安全和易于维护。本文将对在Spring中使用Jd…

    Java 2023年5月20日
    00
  • Spring与Mybatis基于注解整合Redis的方法

    下面我将就“Spring与Mybatis基于注解整合Redis的方法”进行完整讲解,包含以下内容: 1.概述2.准备工作3.整合步骤4.示例说明5.结语 1.概述 Spring与Mybatis是一种非常流行的技术组合,受到了广泛的关注和使用。而Redis则是一种高性能、非关系型的内存数据库,用来作为缓存非常合适。针对这种情况,我们需要一种方法,将Spring…

    Java 2023年6月15日
    00
  • java基础的详细了解第九天

    Java基础的详细了解第九天的攻略如下: 一、集合框架 集合框架是Java中非常重要的一部分内容,也是开发Java应用程序必不可少的一部分。集合框架主要由三个接口和13个类组成,我们需要熟练掌握各个类的使用方法,包括:ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap 等。 1. ArrayList Ar…

    Java 2023年5月26日
    00
  • [PHP]模板引擎Smarty深入浅出介绍

    非常感谢您对我的专业知识的关注,以下是“[PHP]模板引擎Smarty深入浅出介绍”的完整攻略。 什么是Smarty Smarty 是一种 PHP 模板引擎,它是开源的、免费的、遵循 LGPL 协议发布的软件。Smarty 的目标是使设计师和程序员可以相互协作,它对模板的语法进行了规范定义并且大大降低了 PHP 代码在模板中出现的频率,从而使得代码更加易于阅…

    Java 2023年6月15日
    00
合作推广
合作推广
分享本页
返回顶部