面试题:【多线程问题,三个线程A,B,C;C线程依赖B线程的结果执行,怎么控制】

在 Java 中,若需要控制线程间的依赖关系(如 C 线程依赖 B 线程的结果),可以通过以下几种方式实现:

方案 1:使用 CountDownLatch
CountDownLatch 是一个同步工具类,允许一个或多个线程等待其他线程完成操作。
实现步骤:

  1. 定义一个 CountDownLatch,初始计数设为 1(表示 B 线程完成后需要触发一次通知)。
  2. B 线程执行完成后,调用 countDown() 方法减少计数。
  3. C 线程启动时调用 await(),阻塞直到计数变为 0(即 B 线程完成)。
    示例代码:
import java.util.concurrent.CountDownLatch;public class ThreadDependentExample {public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(1);// 启动线程 B,完成后触发 latch.countDown()Thread bThread = new Thread(() -> {System.out.println("B 线程开始执行");// 模拟 B 的处理逻辑try { Thread.sleep(1000); } catch (InterruptedException e) {}System.out.println("B 线程完成");latch.countDown(); // 通知 C 可以执行});// 启动线程 C,等待 B 完成后执行Thread cThread = new Thread(() -> {try {System.out.println("C 线程等待 B 完成");latch.await(); // 阻塞直到 B 完成System.out.println("C 线程开始执行,B 已完成");// C 的处理逻辑} catch (InterruptedException e) {Thread.currentThread().interrupt();System.out.println("C 线程被中断");}});// 启动线程 A(独立执行)Thread aThread = new Thread(() -> {System.out.println("A 线程开始执行");try { Thread.sleep(500); } catch (InterruptedException e) {}System.out.println("A 线程完成");});// 启动所有线程aThread.start();bThread.start();cThread.start();}
}

方案 2:使用 CompletableFuture
CompletableFuture 是 Java 8 引入的高级异步编程工具,支持链式依赖关系。
实现步骤:

  1. 将 B 的任务包装为 CompletableFuture。
  2. 通过 thenRun 或 thenApply 方法,将 C 的任务绑定到 B 的完成后执行。
  3. 线程 A 可独立运行(通过 runAsync 并行执行)。
    示例代码:
import java.util.concurrent.CompletableFuture;public class CompletableFutureExample {public static void main(String[] args) {// 线程 B 的任务CompletableFuture<Void> bFuture = CompletableFuture.runAsync(() -> {System.out.println("B 线程开始执行");try { Thread.sleep(1000); } catch (InterruptedException e) {}System.out.println("B 线程完成");});// 线程 C 的任务绑定在 B 完成后执行bFuture.thenRun(() -> {System.out.println("C 线程开始执行,B 已完成");// C 的处理逻辑});// 线程 A 的任务独立运行CompletableFuture<Void> aFuture = CompletableFuture.runAsync(() -> {System.out.println("A 线程开始执行");try { Thread.sleep(500); } catch (InterruptedException e) {}System.out.println("A 线程完成");});// 等待所有任务完成(可选)try {CompletableFuture.allOf(aFuture, bFuture).get();} catch (Exception e) {e.printStackTrace();}}
}

方案 3:使用 Thread.join()
Thread.join() 方法可以让当前线程等待另一个线程执行完毕。
实现步骤:

  1. 启动线程 B 和 A。
  2. 在 C 线程的 run 方法中调用 bThread.join(),确保 B 完成后再执行 C。
    示例代码:
public class ThreadJoinExample {public static void main(String[] args) {// 启动线程 BThread bThread = new Thread(() -> {System.out.println("B 线程开始执行");try { Thread.sleep(1000); } catch (InterruptedException e) {}System.out.println("B 线程完成");});// 启动线程 C,需等待 B 完成Thread cThread = new Thread(() -> {try {System.out.println("C 线程等待 B 完成");bThread.join(); // 等待 B 线程完成System.out.println("C 线程开始执行,B 已完成");// C 的处理逻辑} catch (InterruptedException e) {Thread.currentThread().interrupt();System.out.println("C 线程被中断");}});// 启动线程 A(独立执行)Thread aThread = new Thread(() -> {System.out.println("A 线程开始执行");try { Thread.sleep(500); } catch (InterruptedException e) {}System.out.println("A 线程完成");});// 启动所有线程aThread.start();bThread.start();cThread.start();}
}

关键注意事项

  1. 线程安全:若 C 需要使用 B 的结果(如共享数据),需确保数据操作线程安全(如通过 volatile、锁或原子类)。
  2. 异常处理:确保线程执行过程中捕获异常,避免程序崩溃。
  3. 资源释放:及时关闭线程池或释放资源,避免内存泄漏。
  4. 性能调优:若任务频繁执行,优先选择 CompletableFuture 或线程池优化性能。

方案对比
| 方法 | 适用场景 | 优点 | 缺点 |
| CountDownLatch | 需要等待多个线程完成后再执行后续任务 | 简单易用,支持多个依赖项 | 需手动管理计数,线程间耦合较紧 |
| CompletableFuture | 复杂异步任务链,需要链式依赖、结果传递 | 高内聚、可组合,支持异常处理和超时 | 学习成本较高,API 较复杂 |
| Thread.join() | 仅需要等待一个线程完成,代码简洁 | 代码简洁,直接调用 | 只能等待单个线程,无法扩展到多个依赖项 |

根据需求选择最合适的方法:
• 若需要链式异步任务,优先使用 CompletableFuture。
• 若需要简单依赖关系,可选 CountDownLatch 或 Thread.join()。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/95571.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/95571.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React useMemo 深度指南:原理、误区、实战与 2025 最佳实践

把“为什么用、怎么用、用错了怎么办”一次讲透&#xff0c;附 React 19 自动优化前瞻。一、useMemo 是什么&#xff1f; 一句话&#xff1a; useMemo 记住&#xff08;缓存&#xff09;昂贵计算结果&#xff0c;只在依赖变化时重新计算。 const memoValue useMemo(() > {…

[ HTML 前端 ] 语法介绍和HBuilderX安装

目录 一. HTML 1.概述 2. 安装前端开发工具 (1)HBuilderX下载 (2)创建html项目和使用 3. HTML基础 1.标签 (1).标签定义: (2).标签结构: (3).标签属性: 2.常用标签: 3.特殊符号: 4.表格(table) (1)基本标签: (2)基本结构: (3)表格属性: 5.表单(form) (1). 表单概述…

Spring Cloud系列—Alibaba Sentinel熔断降级

上篇文章&#xff1a; Spring Cloud系列— Alibaba Sentinel限流https://blog.csdn.net/sniper_fandc/article/details/149944260?fromshareblogdetail&sharetypeblogdetail&sharerId149944260&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link…

Spring Boot 使用 @NotBlank + @Validated 优雅校验参数

在日常开发中&#xff0c;我们常用 if (isBlank(...)) 来判断参数是否为空&#xff0c;但这种方式不仅繁琐&#xff0c;而且容易遗漏。 Spring 生态中推荐使用 JSR-303 校验注解&#xff08;NotBlank、NotNull 等&#xff09;配合 Validated 实现自动校验&#xff0c;大幅减少手…

网络安全(Java语言)简单脚本汇总 (一)

文章目录敏感信息探测脚本源代码思路URL批量存活探测器源代码思路端口扫描器源代码思路 敏感信息探测脚本 源代码/*** description 该脚本通过分析HTTP响应头&#xff0c;来检测可能暴露服务器信息的安全隐患*/import java.io.IOException; import java.net.HttpURLConnection;…

buuctf_NSBlogin_http_upload(极客2019+ACTF2020新生赛)

今天做三1个web 题目&#xff1a;NSB_login用户名有admin&#xff0c;看源码&#xff1a;I like rockyou&#xff01;今天学习到&#xff0c;kali里面有密码爆破的文件叫rockyou.txt&#xff08;/usr/share/wordlists/&#xff09;&#xff08;没kali也可以去https://gitcode.c…

IDEA如何引用brew安装的openjdk

因为 brew 安装的 openjdk@21 目录结构和 IDEA 期望的 JDK 目录不一样。所以默认brew安装的jdk,在IDEA中是无法识别到的。 一、创建软连接 sudo mkdir -p /Library/Java/JavaVirtualMachines sudo ln -sfn /usr/local/opt/openjdk@21/libexec/openjdk.jdk /Library/Java/Java…

【Unity3D】Spine黑线(预乘问题)、贴图边缘裁剪问题

一、黑线问题 Spine正确的导出和Unity导入设置&#xff08;解决黑边/彩条带问题&#xff09;_spine导出的图片有黑边-CSDN博客 采用&#xff08;已解决问题&#xff09; Texture 打包器启用 Premultiply alpha ,禁用Bleed Unity Texture 设置中禁用 sRGB (Color Texture) 和…

嵌入式系统学习Day18(文件编程-系统调用文件IO)

- open#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode); 功能:打开文件 参数:pathname --- 文件名 flags 必选:O_RDONLYO_WRONLY…

Vue浅学

概述在最近的学习任务中了解了 Vue&#xff0c;并对其产生了浓厚的兴趣&#xff0c;现在分享一下我的学习所得关键字其一statestate 是 Vuex 存储中的“状态对象”&#xff0c;用于存储整个应用的共享数据&#xff08;如用户信息、令牌、权限等&#xff09;&#xff0c;比如&am…

机器翻译:Hugging Face库详解

文章目录一、Hugging Face概述1.1 Hugging Face介绍1.2 核心理念&#xff1a;模型即服务&#xff0c;但以开源形式二、核心架构2.1 Transformers库&#xff1a;模型交互的统一接口2.2 Datasets库&#xff1a;高效的数据处理引擎2.3 Tokenizers库&#xff1a;文本与模型的“翻译…

服务器安装gielab社区版

第一步&#xff1a;安装Gitlab 1,使用的是CentOs镜像(服务器最低配置为4核8g内存才行要不然带不动) 登录目标实例。 2,执行如下命令&#xff0c;安装所需依赖。 1 sudo yum install -y curl policycoreutils-python openssh-server 3,执行如下命令&#xff0c;启动SSH服务…

C#报错:System.NullReferenceException:“未将对象引用设置到对象的实例。”

C#使用自定义的类创建数组时&#xff0c;使用时报错&#xff0c;报错内容如下图&#xff1a;原因&#xff1a;C#中的数组是引用类型。当声明自定义类数组时&#xff0c;数组本身会被创建&#xff0c;但其元素&#xff08;即自定义类的实例&#xff09;默认未被实例化&#xff0…

Maven 的 module 管理

一、Maven 的 module 管理 1. 什么是 Maven module&#xff1f; Maven module&#xff08;模块&#xff09;&#xff0c;是 Maven 多模块项目结构&#xff08;multi-module project&#xff09;中的核心概念。它允许你将一个大型项目拆分为若干独立的小项目&#xff08;模块&am…

现在都是APP,小程序抢购,支持浏览器不支持 SSE

在 APP 和小程序抢购场景中&#xff0c;通常不原生支持SSE&#xff08;Server-Sent Events&#xff09;&#xff0c;这与浏览器对 SSE 的支持情况不同&#xff0c;具体如下&#xff1a;APP&#xff1a;一般情况下&#xff0c;APP 端不支持原生 SSE。若使用 UniApp 开发&#xf…

Spring Boot 深度解析:从原理到实践

一、Spring Boot 本质与核心价值 1.1 什么是 Spring Boot&#xff1f; Spring Boot 是 Spring 生态的革命性框架&#xff0c;旨在解决传统 Spring 开发的复杂性。它通过"约定优于配置"&#xff08;Convention Over Configuration&#xff09;理念&#xff0c;提供开箱…

WebSocket-java篇

问题引入消息推送的方式我们要实现&#xff0c;服务器把消息推送到客户端&#xff0c;可以轮训&#xff0c;长轮训还有sseWebSocket理论WebSocket 的由来与核心价值诞生背景&#xff1a;解决 HTTP 协议在实时通信中的固有缺陷&#xff08;单向请求-响应模式&#xff09;核心驱动…

用Python从零开始实现神经网络

反向传播算法用于经典的前馈人工神经网络。 它仍然是训练大型深度学习网络的技术。 在这个教程中&#xff0c;你将学习如何用Python从头开始实现神经网络的反向传播算法。 完成本教程后&#xff0c;您将了解&#xff1a; 如何将输入前向传播以计算输出。如何反向传播错误和…

算法148. 排序链表

题目&#xff1a;给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。示例 1&#xff1a;输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a;输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5] 示例 3&a…

在腾讯云CodeBuddy上实现一个AI聊天助手

在腾讯云CodeBuddy上实现一个AI聊天助手项目 在当今数字化时代&#xff0c;AI聊天助手已经成为一种非常流行的应用&#xff0c;广泛应用于客户服务、智能助手等领域。今天&#xff0c;我们将通过腾讯云CodeBuddy平台&#xff0c;实现一个基于Spring Boot和OpenAI API的AI聊天助…