面试中的线程题
原文链接:线程题大全
Java 并发库同步辅助类
CountDownLatch
工作机制:初始化一个计数器,此计数器的值表示需要等待的事件数量。
提供了两个主要方法:
- await():当一个线程调用此方法时,它将阻塞,直到计数器的值为 0
- countDown():用于减少计数器的值。通常表示一个事件已经发生了(如任务完成),当计数器的值减到 0 时,所有调用 await()并阻塞的线程将被唤醒并继续执行
重要特性:
- 不可重置:一旦计数器的值为 0,就不能再被重置回初识值或其他任何值
- 一次性的:计数值到达 0 后,所有在 await()方法上等待的线程将被释放,而后续的 await()方法调用将立即通过,不会进行阻塞
- 多用途同步工具:能被用于多种目的,等待服务的初始化、一组任务或某个事件的发生
示例:在两个工作线程结束后再调用主线程
CountDownLatch latch = new CountDownLatch(2); // 设定计数器初始值为2// 创建第一个线程,完成某项任务后调用countDown方法
new Thread(() -> {System.out.println("线程1执行...");latch.countDown();System.out.println("线程1完成操作,计数器减一");
}).start();// 创建第二个线程,也是完成某项任务后调用countDown方法
new Thread(() -> {System.out.println("线程2执行...");latch.countDown();System.out.println("线程2完成操作,计数器减一");
}).start();try {// 调用await方法的线程会被阻塞,直到计数器的值变为0latch.await();System.out.println("两个线程的操作均已完成,主线程继续执行");
} catch (InterruptedException e) {e.printStackTrace();
}
CyclicBarrier
工作机制:允许一组线程相互等待到达一个共同屏障点
重要特性:
- 屏障:允许提供一个 Runnable 任务,在所有线程都到达屏障,线程释放前执行该任务。通常用于合并最终结果或者进行某种必须等到所有线程都到达屏障点后才能执行的操作
- 等待线程数:在创建 CyclicBarrier 时,需要指定等待的线程数量。当指定数量的线程都调用 await()方法,表示它们都到达了屏障点,随后这些线程都将被释放
- 超时与中断:线程在调用 await()方法时可以选择设置超时时间,超时或者被中断都将导致线程提前释放,并抛出相应异常
- 重置:释放等待线程后重置计数器。
示例:当四个线程都达到屏障后,打印一句话,然后每个线程继续执行它们的任务
public class CyclicBarrierExample {// 创建一个新的CyclicBarrier,当四个参与者到达时执行屏障操作private CyclicBarrier barrier = new CyclicBarrier(4, () -> System.out.println("所有线程到达屏障点,屏障操作执行!"));public void startTask(String name) {new Thread(() -> {System.out.println(name + "开始执行任务...");// 模拟任务耗时try {Thread.sleep((int)(Math.random() * 1000));} catch (InterruptedException e) {e.printStackTrace();}System.out.println(name + "到达屏障点,等待其他线程...");try {// 调用await方法等待其他线程都到达屏障点barrier.await();} catch (Exception e) {e.printStackTrace();}System.out.println(name + "继续执行后续操作");}).start();}public static void main(String[] args) {CyclicBarrierExample example = new CyclicBarrierExample();example.startTask("线程A");example.startTask("线程B");example.startTask("线程C");example.startTask("线程D"); // 当所有四个线程达到屏障点,将一起释放,然后执行屏障操作}
}
线程交叉打印模版
public class CrossPrinter {private int state;private final int printCount;public CrossPrinter(int printCount) {// state用来确定下次打印this.state = 0;// 打印次数this.printCount = printCount;}public void printLetter(String Letter, int crossState ,int curState) {for (int i = 0; i < printCount; i++) {synchronized (this) {while (state % crossState != curState) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() + ":" + Letter);state++;notifyAll();}}}public static void main(String[] args) {CrossPrinter crossPrinter = new CrossPrinter(5);// Thread A打印"A"new Thread(() -> crossPrinter.printLetter("A", 2,0), "Thread A").start();// Thread B打印"B"new Thread(() -> crossPrinter.printLetter("B", 2,1), "Thread B").start();}}
上述完成了两线程交叉打印"A"、“B”,具体说明下
- printCount:控制交叉打印次数
- state:全局变量,指明线程已经执行多少次了
- crossState:指明有多少个线程进行交叉
- curState:指明当前线程
- Letter:当前线程打印内容
可用于:
- 多线程交叉打印 A、B、C…
- 两线程交叉打印奇偶数
三线程交叉打印 A、B、C
模版中是两线程交叉打印 A、B,只需要做简单替换就能实现三线程交叉打印 A、B、C
crossState:3
新增线程 C 如下
// Thread A打印"A"
new Thread(() -> crossPrinter.printLetter("A", 3,0), "Thread A").start();// Thread B打印"B"
new Thread(() -> crossPrinter.printLetter("B", 3,1), "Thread B").start();// Thread C打印"C"
new Thread(() -> crossPrinter.printLetter("C", 3,2), "Thread C").start();
两线程交叉打印奇偶数
比如要求打印到两线程交叉打印到 10
state 控制线程进行轮次,此时可以换为 while 条件,用来控制跳出循环
crossState:2,表示两线程
完整代码如下:
public class CrossPrinter {private int state;private final int printCount;public CrossPrinter(int printCount) {// state用来确定下次打印this.state = 0;// printCount表示打印次数this.printCount = printCount;}public void printNumber(int crossState ,int curState) {while (state < printCount) {synchronized (this) {while (state % crossState != curState) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() + ":" + state);state++;notifyAll();}}}public static void main(String[] args) {CrossPrinter crossPrinter = new CrossPrinter(10);// Thread A打印偶数new Thread(() -> crossPrinter.printNumber(2,0), "Thread A").start();// Thread B打印奇数new Thread(() -> crossPrinter.printNumber(2,1), "Thread B").start();}}
三线程交叉打印斐波那契数列
新增 oneNum、twoNum 来记录前两个数
完整代码如下
public class CrossPrinter {private int state;private int oneNum;private int twoNum;private final int printCount;public CrossPrinterThree(int printCount) {this.state = 3;this.oneNum = 1;this.twoNum = 1;this.printCount = printCount;}public static void main(String[] args) {CrossPrinterThree crossPrinterThree = new CrossPrinter(10);// 三线程交叉打印斐波那契数列new Thread(() -> crossPrinterThree.printNum(3, 0), "Thread-A").start();new Thread(() -> crossPrinterThree.printNum(3, 1), "Thread-B").start();new Thread(() -> crossPrinterThree.printNum(3, 2), "Thread-C").start();}private void printNum(int crossState, int curState) {while (state < printCount) {synchronized (this) {while (state % crossState != curState) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}int curNum = oneNum + twoNum;System._out_.println(Thread._currentThread_().getName() + ":" + curNum);// 更新前两个数oneNum = twoNum;twoNum = curNum;state++;notifyAll();}}}}
多线程任务执行 A -> B, A -> C
实现方案:CountDownLatch
- 为线程 B、C 分别设置 CountDownLatch 锁,当线程 A 执行后,唤醒线程 B、C 的 CountDownLatch 锁
public class MultiThreadTaskExecution {// 使用两个初始计数为1的CountDownLatch来实现一对多的通知机制private CountDownLatch latchToB = new CountDownLatch(1);private CountDownLatch latchToC = new CountDownLatch(1);public void taskA() {System.out.println("任务A执行中...");try {Thread.sleep(100); // 模拟任务A执行时间} catch (InterruptedException e) {e.printStackTrace();}System.out.println("任务A执行完毕,通知任务B、C开始执行...");latchToB.countDown();latchToC.countDown();}public void taskB() {try {latchToB.await();System.out.println("任务B执行中...");Thread.sleep(100); // 模拟任务B执行时间System.out.println("任务B执行完毕...");} catch (InterruptedException e) {e.printStackTrace();}}public void taskC() {try {latchToC.await();System.out.println("任务C执行中...");Thread.sleep(100); // 模拟任务C执行时间System.out.println("任务C执行完毕...");} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args) {MultiThreadTaskExecution taskExecution = new MultiThreadTaskExecution();new Thread(taskExecution::taskB).start();new Thread(taskExecution::taskC).start();new Thread(taskExecution::taskA).start();}}
线程 A、B、C 都到达屏障点才执行后续操作
实现方案:CyclicBarrier
- 设置屏障数量 3,同时可设置一个 Runnable 任务,当都达到时输出一句话。
public class CyclicBarrierOne {// 创建一个新的CyclicBarrier,当3个参与者到达时执行屏障操作private CyclicBarrier barrier = new CyclicBarrier(3, () -> System._out_.println("所有线程到达屏障点,屏障操作执行!"));public static void main(String[] args) {CyclicBarrierOne cyclicBarrierOne = new CyclicBarrierOne();new Thread(() -> cyclicBarrierOne.startTask(), "Thread-A").start();new Thread(() -> cyclicBarrierOne.startTask(), "Thread-B").start();new Thread(() -> cyclicBarrierOne.startTask(), "Thread-C").start();}private void startTask() {System._out_.println(Thread._currentThread_().getName() + "开始执行任务...");try {Thread._sleep_(100);} catch (InterruptedException e) {e.printStackTrace();}System._out_.println(Thread._currentThread_().getName() + "到达屏障点,等待其他线程...");try {barrier.await();} catch (Exception e) {e.printStackTrace();}System._out_.println(Thread._currentThread_().getName() + "继续执行后续操作");}}
10 个线程同时启动
public class SimultaneousStart {private static final int _N _= 10;_// 创建一个CountDownLatch用于线程启动的信号_
_ _private static final CountDownLatch _startSignal _= new CountDownLatch(1);_// 创建一个 CountDownLatch 用于等待所有线程完成的信号_
_ _private static final CountDownLatch _doneSignal _= new CountDownLatch(_N_);public static void main(String[] args) throws InterruptedException {Runnable task = () -> {try {_startSignal_.await(); _// 等待启动信号_
_ _System._out_.println(Thread._currentThread_().getName() + " has started");Thread._sleep_(2000); _// 模拟任务执行_
_ _System._out_.println(Thread._currentThread_().getName() + " has finished");} catch (InterruptedException e) {Thread._currentThread_().interrupt();} finally {_doneSignal_.countDown(); _// 完成信号_
_ _}};_// 创建并启动N个线程_
_ _for (int i = 0; i < _N_; i++) {new Thread(task, "Thread-" + (i + 1)).start();}_// 主线程等待片刻,确保所有线程已经启动并在等待_
_ _Thread._sleep_(1000);System._out_.println("All threads are ready, starting now!");_startSignal_.countDown(); _// 发出启动信号_
_ doneSignal_.await(); _// 等待所有线程完成__ _System._out_.println("All threads have finished executing.");}
}
死锁
public class DeadlockExample {// 创建两个资源
private static final Object _resourceOne _= new Object();
private static final Object _resourceTwo _= new Object();public static void main(String[] args) {new Thread(() -> {synchronized (resourceOne) {System.out.println(Thread.currentThread().getName() + "locked resource1");try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (resourceTwo) {System.out.println(Thread.currentThread().getName() + "locked resource2");}}}, "Thread-A").start();new Thread(() -> {synchronized (resourceTwo) {System.out.println(Thread.currentThread().getName() + "locked resource2");try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (resourceOne) {System.out.println(Thread.currentThread().getName() + "locked resource1");}}}, "Thread-B").start();}}
多个线程同时争抢同一把锁,阻塞情况下唤醒指定线程
- 自定义条件变量
- 标志变量
自定义条件变量
public class CustomLockExample {private final Lock lock = new ReentrantLock();private final Condition conditionA = lock.newCondition();private final Condition conditionB = lock.newCondition();private void methodA() throws InterruptedException {lock.lock();try {System._out_.println("Thread A is waiting");conditionA.await();System._out_.println("Thread A is resumed");} finally {lock.unlock();}}private void methodB() throws InterruptedException {lock.lock();try {System._out_.println("Thread B is waiting");conditionB.await();System._out_.println("Thread B is resumed");} finally {lock.unlock();}}private void resumeA() {lock.lock();try {conditionA.signal(); _// Wake up one thread waiting on conditionA_
_ _System._out_.println("Signaled Thread A");} finally {lock.unlock();}}private void resumeB() {lock.lock();try {conditionB.signal(); _// Wake up one thread waiting on conditionB_
_ _System._out_.println("Signaled Thread B");} finally {lock.unlock();}}public static void main(String[] args) throws InterruptedException {CustomLockExample example = new CustomLockExample();Thread threadA = new Thread(() -> {try {example.methodA();} catch (InterruptedException e) {e.printStackTrace();}});Thread threadB = new Thread(() -> {try {example.methodB();} catch (InterruptedException e) {e.printStackTrace();}});threadA.start();threadB.start();Thread._sleep_(2000); _// Pause to ensure threads reach wait state__ _example.resumeA(); _// Signal threadA_
_ _Thread._sleep_(2000);example.resumeB(); _// Signal threadB_
_ _}
}
标志变量
public class FlagBasedControl {private final Object lock = new Object();private volatile boolean isThreadAWake = false;private void methodA() throws InterruptedException {synchronized (lock) {while (!isThreadAWake) {System._out_.println("Thread A is waiting");lock.wait();}}System._out_.println("Thread A is resumed and resetting flag");isThreadAWake = false; _// Reset the flag for next use }_
_ _}private void resumeA() {synchronized (lock) {isThreadAWake = true;lock.notifyAll(); _// Wake up all threads, but only Thread A will proceed_
_ _System._out_.println("Signaled Thread A");}}public static void main(String[] args) throws InterruptedException {FlagBasedControl example = new FlagBasedControl();Thread threadA = new Thread(() -> {try {example.methodA();} catch (InterruptedException e) {Thread._currentThread_().interrupt();}});threadA.start();Thread._sleep_(2000); _// Pause to ensure thread reaches wait state__ _example.resumeA(); _// Signal threadA_
_ _}
}
相关文章:
面试中的线程题
原文链接:线程题大全 Java 并发库同步辅助类 CountDownLatch 工作机制:初始化一个计数器,此计数器的值表示需要等待的事件数量。 提供了两个主要方法: await():当一个线程调用此方法时,它将阻塞&#…...
济南国网数字化培训班学习笔记-第三组-2-电力通信光缆网认知
电力通信光缆网认知 光缆网架构现状 基础底座 电路系统是高度复杂,实时性、安全性、可靠性要求极高的巨系统,必须建设专用通信网 相伴相生 电力系统是由发电、输电、变电、配电、用电等一次设施,及保障其正常运行的保护、自动化、通信等…...

前端动画库 Anime.js 的V4 版本,兼容 Vue、React
前端动画库 Anime.js 更新了 V4 版本,并对其官网进行了全面更新,增加了许多令人惊艳的效果,尤其是时间轴动画效果,让开发者可以更精确地控制动画节奏。 这一版本的发布不仅带来了全新的模块化 API 和显著的性能提升,还…...

用 PyTorch 从零实现简易GPT(Transformer 模型)
用 PyTorch 从零实现简易GPT(Transformer 模型) 本文将结合示例代码,通俗易懂地拆解大模型(Transformer)从数据预处理到推理预测的核心组件与流程,并通过 Mermaid 流程图直观展示整体架构。文章结构分为四…...
前端JSON序列化中的隐形杀手:精度丢失全解析与实战解决方案
当你在电商平台看到订单ID从 “1298035313029456899” 变成 “1298035313029456900”,或者在金融系统中发现账户余额 100.01 元变成了 100.00999999999999 元时,这很可能遭遇了前端开发中最隐蔽的陷阱之一 —— JSON序列化精度丢失。本文将深入解析这一问…...

【通用大模型】Serper API 详解:搜索引擎数据获取的核心工具
Serper API 详解:搜索引擎数据获取的核心工具 一、Serper API 的定义与核心功能二、技术架构与核心优势2.1 技术实现原理2.2 对比传统方案的突破性优势 三、典型应用场景与代码示例3.1 SEO 监控系统3.2 竞品广告分析 四、使用成本与配额策略五、开发者注意事项六、替…...

Spring3+Vue3项目中的知识点——JWT
全称:JOSN Web Token 定义了一种简洁的、自包含的格式,用于通信双方以json数据格式的安全传输信息 组成: 第一部分:Header(头),记录令牌类型、签名算法等。 第二部分:Payload&am…...

python3GUI--智慧交通分析平台:By:PyQt5+YOLOv8(详细介绍)
文章目录 一.前言二.效果预览1.目标识别与检测2.可视化展示1.车流量统计2. 目标类别占比3. 拥堵情况展示4.目标数量可视化 3.控制台4.核心内容区1.目标检测参数2.帧转QPixmap3.数据管理 5.项目结构 三.总结 平台规定gif最大5M,所以…...

Linux任务管理与守护进程
一、任务管理 (一)进程组、作业、会话概念 (1)进程组概念:进程组是由一个或多个进程组成的集合,这些进程在某些方面具有关联性。在操作系统中,进程组是用于对进程进行分组管理的一种机制。每个…...

C#里与嵌入式系统W5500网络通讯(2)
在嵌入式代码里,需要从嵌入式的MCU访问W5500芯片。 这个是通过SPI通讯来实现的,所以要先连接SPI的硬件通讯线路。 接着下来,就是怎么样访问这个芯片了。 要访问这个芯片,需要通过SPI来发送数据,而发送数据又要有一定的约定格式, 于是芯片厂商就定义下面的通讯格式: …...

EMQX开源版安装指南:Linux/Windows全攻略
EMQX开源版安装教程-linux/windows 因最近自己需要使用MQTT,需要搭建一个MQTT服务器,所以想到了很久以前用到的EMQX。但是当时的EMQX使用的是开源版的,在官网可以直接下载。而现在再次打开官网时发现怎么也找不大开源版本了,所以…...

【计算机视觉】OpenCV实战项目:GraspPicture 项目深度解析:基于图像分割的抓取点检测系统
GraspPicture 项目深度解析:基于图像分割的抓取点检测系统 一、项目概述项目特点 二、项目运行方式与执行步骤(一)环境准备(二)项目结构(三)执行步骤 三、重要逻辑代码解析(一&#…...

MySQL 数据库备份与还原
作者:IvanCodes 日期:2025年5月18日 专栏:MySQL教程 思维导图 备份 (Backup) 与 冗余 (Redundancy) 的核心区别: 🎯 备份是指创建数据的副本并将其存储在不同位置或介质,主要目的是在发生数据丢失、损坏或逻辑错误时进…...

Kubernetes控制平面组件:Kubelet详解(四):gRPC 与 CRI gRPC实现
云原生学习路线导航页(持续更新中) kubernetes学习系列快捷链接 Kubernetes架构原则和对象设计(一)Kubernetes架构原则和对象设计(二)Kubernetes架构原则和对象设计(三)Kubernetes控…...

javax.servlet.Filter 介绍-笔记
1.javax.servlet.Filter 简介 javax.servlet.Filter 是 Java Servlet API 中的一个核心接口,用于在请求到达目标资源(如 Servlet 或 JSP)之前或响应返回给客户端之前执行预处理或后处理操作。它常用于实现与业务逻辑无关的通用功能ÿ…...
从40秒到11毫秒:TiDB环境下一次SQL深潜优化实战
作者: meathill 原文来源: https://tidb.net/blog/edb6061b 在数据库应用中,慢SQL是常见的性能瓶颈。本文将详细记录一次针对TiDB Cloud v7.5.2环境中复杂评论查询的SQL优化过程,如何通过分析执行计划、添加索引、改写SQL&…...

Win 11开始菜单图标变成白色怎么办?
在使用windows 11的过程中,有时候开始菜单的某些程序图标变成白色的文件形式,但是程序可以正常打开,这个如何解决呢? 这通常是由于快捷方式出了问题,下面跟着操作步骤来解决吧。 1、右键有问题的软件,打开…...

入门OpenTelemetry——应用自动埋点
埋点 什么是埋点 埋点,本质就是在你的应用程序里,在重要位置插入采集代码,比如: 收集请求开始和结束的时间收集数据库查询时间收集函数调用链路信息收集异常信息 这些埋点数据(Trace、Metrics、Logs)被…...

C语言链表的操作
初学 初学C语言时,对于链表节点的定义一般是这样的: typedef struct node {int data;struct node *next; } Node; 向链表中添加节点: void addNode(Node **head, int data) {Node *newNode (Node*)malloc(sizeof(Node));newNode->dat…...

芯片生态链深度解析(二):基础设备篇——人类精密制造的“巅峰对决”
【开篇:设备——芯片工业的“剑与盾”】 当ASML的EUV光刻机以每秒5万次激光脉冲在硅片上雕刻出0.13nm精度的电路(相当于在月球表面精准定位一枚二维码),当国产28nm光刻机在华虹产线实现“从0到1”的突破,这场精密制造…...

C语言指针深入详解(二):const修饰指针、野指针、assert断言、指针的使用和传址调用
目录 一、const修饰指针 (一)const修饰变量 (二)const 修饰指针变量 二、野指针 (一)野指针成因 1、指针未初始化 2、指针越界访问 3、指针指向的空间释放 (二)如何规避野指…...

【unity游戏开发——编辑器扩展】使用EditorGUI的EditorGUILayout绘制工具类在自定义编辑器窗口绘制各种UI控件
注意:考虑到编辑器扩展的内容比较多,我将编辑器扩展的内容分开,并全部整合放在【unity游戏开发——编辑器扩展】专栏里,感兴趣的小伙伴可以前往逐一查看学习。 文章目录 前言常用的EditorGUILayout控件专栏推荐完结 前言 EditorG…...

Linux基础第三天
系统时间 date命令,date中文具有日期的含义,利用该命令可以查看或者修改Linux系统日期和时间。 基本格式如下: gecubuntu:~$ date gecubuntu:~$ date -s 日期时间 // -s选项可以设置日期和时间 文件权限 chmod命令,是英文…...

MoodDrop:打造一款温柔的心情打卡单页应用
我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 起心动念:我想做一款温柔的情绪应用 「今天的你,心情如何?」 有时候&#x…...

接口——类比摄像
最近迷上了买相机,大疆Pocket、Insta Go3、大疆Mini3、佳能50D、vivo徕卡人像大师(狗头),在买配件的时候,发现1/4螺口简直是神中之神,这个万能接口让我想到计算机设计中的接口,遂有此篇—— 接…...
【上位机——WPF】布局控件
布局控件 常用布局控件Panel基类Grid(网格)UniformGrid(均匀分布)StackPanel(堆积面板)WrapPanel(换行面板)DockerPanel(停靠面板)Canvas(画布布局)Border(边框)GridSplitter(分割窗口)常用布局控件 Grid:网格,根据自定义行和列来设置控件的布局StackPanel:栈式面板,包含的…...
深入解析Spring Boot与Kafka集成:构建高性能消息驱动应用
深入解析Spring Boot与Kafka集成:构建高性能消息驱动应用 引言 在现代分布式系统中,消息队列是实现异步通信和解耦的重要组件。Apache Kafka作为一种高性能、分布式的消息系统,被广泛应用于大数据和实时数据处理场景。本文将详细介绍如何在…...

二十、案例特训专题3【系统设计篇】web架构设计
一、前言 二、内容提要 三、单机到应用与数据分离 四、集群与负载均衡 五、集群与有状态无状态服务 六、ORM 七、数据库读写分离 八、数据库缓存Memcache与Redis 九、Redis数据分片 哈希分片如果新增分片会很麻烦,需要把之前数据取出来再哈希除模 一致性哈希分片是…...

【数据结构与算法】ArrayList 与顺序表的实现
目录 一、List 接口 1.1 List 接口的简单介绍 1.1 常用方法 二、顺序表 2.1 线性表的介绍 2.2 顺序表的介绍 2.3 顺序表的实现 2.3.1 前置条件:自定义异常 2.3.2 顺序表的初始化 2.3.2 顺序表的实现 三、ArrayList 实现类 3.1 ArrayList 的两种使用方式 3.2 Array…...
处理金融数据,特别是股票指数数据,以计算和分析RSRS(相对强度指数)
Python脚本,用于处理金融数据,特别是股票指数数据,以计算和分析RSRS(相对强度指数)指标。以下是代码的逐部分解释: 1. **导入库**: - `pandas`:用于数据处理和CSV文件操作。 - `numpy`:用于数值计算。 - `ElasticNet`:来自`sklearn.linear_model`,用于线性…...