0

0

Java多线程中正确同步 getter 与确保主线程等待子线程完成的实践指南

心靈之曲

心靈之曲

发布时间:2026-02-19 09:04:03

|

495人浏览过

|

来源于php中文网

原创

Java多线程中正确同步 getter 与确保主线程等待子线程完成的实践指南

本文详解为何仅对 run() 和 getmax() 方法加 synchronized 无法真正解决竞态问题,并提供基于 join()、future 和线程安全封装的三种专业级解决方案。

本文详解为何仅对 run() 和 getmax() 方法加 synchronized 无法真正解决竞态问题,并提供基于 join()、future 和线程安全封装的三种专业级解决方案。

在 Java 多线程编程中,一个常见误区是认为给 run() 或 getter 方法加上 synchronized 就能“自动保证线程执行顺序”或“强制主线程等待”。但事实恰恰相反:synchronized 仅保证临界区互斥访问,不提供线程执行依赖关系(如“等待完成”语义)。原始代码的问题本质是缺少显式的线程同步机制来协调主线程与工作线程的执行时序——主线程在子线程尚未完成计算时便调用 getMax(),读取到的是未初始化或过期的 max 值(默认为 0),导致结果错误。

❌ 错误方案解析:为什么 synchronized run() 和 synchronized getMax() 是伪解?

public synchronized void run() { /* ... */ }  // ❌ 危险!串行化所有任务
public synchronized int getMax() { return max; }
  • synchronized run() 会使所有 MaxTask 实例串行执行,彻底丧失并行性,违背多线程初衷;
  • synchronized getMax() 仅防止多个线程同时读取 max,但无法保证读取时 max 已被正确写入(即缺乏 happens-before 关系);
  • 更关键的是:synchronized 不等价于 join() —— 它不阻塞主线程,也不声明“我必须等你跑完”。

因此,该做法属于“用错工具治错病”,表面看似“加了锁就安全”,实则掩盖了根本缺陷。

✅ 正确方案一:使用 Thread.join() 显式等待(最直接)

这是最符合原代码结构的修复方式,只需在启动所有线程后,插入等待逻辑:

// 启动所有线程后,立即 join
for (int i = 0; i < workers; i++) {
    tasks[i].start();
}
// 等待全部完成(关键!)
for (int i = 0; i < workers; i++) {
    tasks[i].join(); // 主线程在此阻塞,直到 tasks[i] 终止
}

// 此时再读取结果,100% 安全
int maxmax = tasks[0].getMax();
for (int i = 1; i < workers; i++) {
    maxmax = Math.max(maxmax, tasks[i].getMax());
}
System.out.println("maxmax=" + maxmax);

✅ 优势:语义清晰、零额外依赖、适用于简单场景。
⚠️ 注意:join() 可能抛出 InterruptedException,生产环境应合理处理(如恢复中断状态)。

✅ 正确方案二:使用 ExecutorService + Future(推荐工业级实践)

告别手动管理 Thread,改用高层抽象,兼具安全性与可扩展性:

NewsBang
NewsBang

盛大旗下AI团队推出的智能新闻阅读App

下载

立即学习Java免费学习笔记(深入)”;

import java.util.concurrent.*;

public class MaxTaskCallable implements Callable<Integer> {
    private final int[] arr;
    private final int first, last;

    public MaxTaskCallable(int[] arr, int first, int last) {
        this.arr = arr;
        this.first = first;
        this.last = last;
    }

    @Override
    public Integer call() throws Exception {
        int max = arr[first];
        for (int i = first + 1; i <= last; i++) {
            if (arr[i] > max) max = arr[i];
        }
        return max;
    }
}

// Main 中调用:
ExecutorService executor = Executors.newFixedThreadPool(workers);
List<Future<Integer>> futures = new ArrayList<>();

for (int i = 0; i < workers; i++) {
    futures.add(executor.submit(new MaxTaskCallable(arr, first, last)));
    first = last + 1;
}

// 收集结果(自动等待完成)
int maxmax = Integer.MIN_VALUE;
for (Future<Integer> future : futures) {
    maxmax = Math.max(maxmax, future.get()); // get() 阻塞直至计算完成
}

executor.shutdown();
System.out.println("maxmax=" + maxmax);

✅ 优势:资源复用、异常传播明确、天然支持超时控制(future.get(5, TimeUnit.SECONDS))、易于监控与扩展。
? 提示:Future.get() 是线程安全的,无需额外同步 getMax()。

✅ 正确方案三:线程安全的结果容器(适合复杂状态共享)

若需在运行中动态更新共享状态(如累计统计),可封装 AtomicInteger 或 ReentrantLock:

public class MaxTaskSafe extends Thread {
    private final int[] arr;
    private final int first, last;
    private final AtomicInteger result; // 线程安全容器

    public MaxTaskSafe(int[] arr, int first, int last, AtomicInteger result) {
        this.arr = arr;
        this.first = first;
        this.last = last;
        this.result = result;
    }

    @Override
    public void run() {
        int localMax = arr[first];
        for (int i = first + 1; i <= last; i++) {
            if (arr[i] > localMax) localMax = arr[i];
        }
        result.accumulateAndGet(localMax, Math::max); // 原子更新最大值
    }
}

// 使用:
AtomicInteger globalMax = new AtomicInteger(Integer.MIN_VALUE);
for (int i = 0; i < workers; i++) {
    new MaxTaskSafe(arr, first, last, globalMax).start();
    first = last + 1;
}
// 等待所有线程结束(仍需 join 或 CountDownLatch)
// ...
System.out.println("maxmax=" + globalMax.get());

总结:关键原则

原则 说明
join() ≠ synchronized join() 解决 线程生命周期依赖;synchronized 解决 数据竞争。二者目的不同,不可替代。
避免过度同步 同步 run() 会扼杀并行性;同步 getter 仅防并发读,不保可见性——除非配合 volatile 或 join()。
优先选用高级 API ExecutorService + Future 比裸 Thread 更健壮、易维护、易测试。
明确内存模型契约 任何跨线程数据传递,必须建立 happens-before 关系(join()、volatile 写后读、synchronized 退出/进入等)。

遵循以上实践,你将不仅能修复当前 bug,更能构建出真正可靠、可演进的并发程序。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

71

2025.10.23

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

675

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

368

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

26

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

24

2026.01.21

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

98

2026.02.06

Java 并发编程高级实践
Java 并发编程高级实践

本专题深入讲解 Java 在高并发开发中的核心技术,涵盖线程模型、Thread 与 Runnable、Lock 与 synchronized、原子类、并发容器、线程池(Executor 框架)、阻塞队列、并发工具类(CountDownLatch、Semaphore)、以及高并发系统设计中的关键策略。通过实战案例帮助学习者全面掌握构建高性能并发应用的工程能力。

94

2025.12.01

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

660

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

203

2026.02.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3.7万人学习

C# 教程
C# 教程

共94课时 | 9.8万人学习

Java 教程
Java 教程

共578课时 | 68.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号