在使用线程的代码实现层面
2026/5/1 2:05:52 网站建设 项目流程

我们在写代码的时候

如果需要提高接口的响应速度
某段代码的成功失败,不能阻碍主线程执行

这些业务场景
都需要使用到开启线程

我们就来了解一下
1.什么是线程,要了解哪些基础信息
2.java中提供了哪些机制来使用线程
3.使用这写机制,在项目中要注意什么

这是一个很实际的问题。你提到的「提高接口响应速度」和「某段代码成败不阻碍主线程」,核心就是异步执行,而线程是实现异步的基础。

我们按你的三个问题逐一拆解。

1. 什么是线程?要了解哪些基础信息?

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。

理解线程,你需要掌握这几个基础概念:

概念说明对你写代码的意义
主线程应用启动时自动创建,负责处理UI事件、用户交互等核心流程你的“不能阻碍主线程” → 就是把耗时操作移出主线程
子线程程序员手动创建,处理耗时任务(网络请求、文件IO、复杂计算)成功/失败不影响主线程响应
并发(Concurrency)多个任务在同一时间段内交替执行(单核CPU也能做到)提升资源利用率
并行(Parallelism)多个任务在同一时刻同时执行(需要多核CPU)真正提速的关键
线程生命周期新建 → 就绪 → 运行 → 阻塞 → 死亡控制任务何时执行、何时结束

💡最重要的一条规则:永远不要在主线程序执行耗时不可预测的操作(比如网络请求、大量数据库查询、文件读写)。

2. Java中提供了哪些机制来使用线程?

Java 演进多年,提供了从底层到高层的多种线程机制:

① 原生 Thread 类(最底层,几乎不用了)

newThread(()->{// 你的耗时任务doSomethingSlow();}).start();

⚠️ 问题:资源开销大、难以管理、易出 bug。

② Runnable + Thread(比①好一点)

Runnabletask=()->doSomething();newThread(task).start();

仍存在资源管理问题,生产环境不推荐直接使用。

③ ExecutorService + 线程池(推荐使用)

ExecutorServiceexecutor=Executors.newFixedThreadPool(10);executor.submit(()->doSomething());

✅ 优点:复用线程、控制最大并发、统一管理。

④ Future / CompletableFuture(获取异步结果)

CompletableFuture<Void>future=CompletableFuture.runAsync(()->{// 异步执行,不关心结果doSomething();});// 如果某段代码需要等待多个异步任务完成CompletableFuture.allOf(future1,future2).join();

⑤ @Async 注解(Spring 环境最方便)

@ServicepublicclassOrderService{@AsyncpublicvoidsendNotification(){// 这个方法的执行不会阻塞调用方}}

需要配合@EnableAsync和自定义线程池使用。

⑥ 消息队列(跨进程/跨服务的终极方案)

当线程池也无法承载或需要持久化时,用 RabbitMQ、Kafka 等。

3. 使用这些机制,在项目中要注意什么?

你提到的「某段代码的成功失败不能阻碍主线程」,这句话其实隐含了典型的坑。以下是最关键的注意事项:

⚠️ 注意1:子线程的异常主线程是感知不到的

// ❌ 错误写法:异常会静默吞掉,你不知道executor.submit(()->{thrownewRuntimeException("失败了");});// ✅ 正确:必须捕获并记录日志executor.submit(()->{try{riskyOperation();}catch(Exceptione){log.error("异步任务执行失败",e);// 可选:通知告警、写入失败记录表、重试}});

⚠️ 注意2:线程池必须自定义,不要用 Executors 的快捷方法

// ❌ 危险:Executors.newFixedThreadPool(100) 的队列无限长,高并发下OOM// ❌ Executors.newCachedThreadPool() 线程数无上限// ✅ 推荐:直接使用 ThreadPoolExecutorThreadPoolExecutorexecutor=newThreadPoolExecutor(5,// 核心线程数20,// 最大线程数60L,TimeUnit.SECONDS,newLinkedBlockingQueue<>(100),// 有界队列,防止堆积爆炸newThreadFactoryBuilder().setNameFormat("async-task-%d").build(),newThreadPoolExecutor.CallerRunsPolicy()// 拒绝策略:让调用线程自己执行);

⚠️ 注意3:上下文传递问题(用户信息、链路追踪)

子线程默认拿不到主线程的:

  • 用户认证信息(Request 上下文)
  • MDC 日志链路 ID
  • 事务(@Transactional不会传播到子线程)
// 解决方案:手动传参 或 使用 TransmittableThreadLocal// 或者 Spring 的 @Async 配合 TaskDecorator

⚠️ 注意4:JVM 关闭时线程池未优雅关闭

应用发布时,如果线程池还在执行任务,直接 kill 会导致数据丢失。

@PreDestroypublicvoiddestroy(){executor.shutdown();// 拒绝新任务try{if(!executor.awaitTermination(30,TimeUnit.SECONDS)){executor.shutdownNow();// 强制关闭}}catch(InterruptedExceptione){executor.shutdownNow();}}

⚠️ 注意5:确认你真的需要「不关心结果」还是「需要结果但不阻塞」

场景方案
完全不关心成功/失败(日志、埋点、发通知)executor.submit()@Asyncvoid 方法
需要结果但不想阻塞主线程CompletableFuture.supplyAsync()+thenApply()回调
需要结果且在某个超时时间内等待future.get(3, TimeUnit.SECONDS)并处理 TimeoutException

总结一句

线程是「不阻塞主线程」的工具,但用错线程池、不处理异常、不考虑关闭,反而会制造更难排查的故障。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询