讲师中心 微信公众号
AI工具推荐 视频效率加速

在Java里如何避免共享数据的竞态条件_Java多线程共享数据同步机制解析

梦杰同学_1406

梦杰同学_1406

发布时间:2026-02-08 12:15:09

|

142人浏览过

|

来源于php中文网

原创

应优先用 synchronized 块保护临界区而非整个方法,避免过度同步;锁对象须私有不可变;简单操作优先用 AtomicInteger 等原子类;复杂逻辑选 ReentrantLock;volatile 仅保可见性与有序性,不保证原子性。

在java里如何避免共享数据的竞态条件_java多线程共享数据同步机制解析

用 synchronized 块保护临界区,而不是整个方法

方法级同步(synchronized 修饰符加在方法上)容易过度锁住,拖慢并发性能。真正需要保护的只是读写共享变量的那一小段逻辑——也就是临界区。

常见错误是把整个 run() 或业务方法都标为 synchronized,结果多个线程串行执行,失去多线程意义。

  • 只对共享变量的读写操作加锁,例如 synchronized(lockObj) { count++; }
  • 锁对象要私有且不可变,避免被外部误用或泄露;推荐用 private final Object lock = new Object();
  • 不要用 this 或类对象(MyClass.class)作锁,除非你明确控制全部同步点

优先使用 java.util.concurrent.atomic 包中的原子类

对简单计数、标志位、引用更新这类操作,AtomicInteger、AtomicBoolean、AtomicReference 比手动加锁更轻量、更安全。

它们底层依赖 CPU 的 CAS(Compare-And-Swap)指令,无锁但保证可见性和原子性,避免了死锁和锁竞争开销。

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

Alibabacloud Sdk Client Initialization For Java
Alibabacloud Sdk Client Initialization For Java

在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。

下载
  • count.incrementAndGet() 替代 synchronized 块里的 count++
  • 注意:原子类只保证单个操作的原子性,复合操作(如“先读再条件更新”)仍需 synchronized 或 StampedLock
  • 不支持像 wait()/notify() 这类协作机制,别试图在原子类上做线程等待

用 ReentrantLock 替代内置锁,当需要超时、可中断或公平性控制时

synchronized 简单可靠,但功能固定:不可中断、不支持超时、非公平(可能饥饿)。一旦遇到这些需求,就得换 ReentrantLock。

典型场景包括:防止线程无限阻塞、响应中断请求、或确保长等待线程最终能获取锁。

  • 必须显式调用 lock.lock() 和 lock.unlock(),且 unlock() 要放在 finally 块中
  • tryLock(long, TimeUnit) 可设超时,避免死等;lockInterruptibly() 支持中断响应
  • 开启公平模式(new ReentrantLock(true))会显著降低吞吐量,仅在确实存在饥饿问题时启用

别忽略 volatile 的适用边界:它不解决竞态,只保可见性与有序性

很多开发者误以为加了 volatile 就能安全共享变量,结果依然出现诡异的计算错误。它只保证写操作对其他线程立即可见,并禁止指令重排序,但不保证复合操作的原子性。

比如 volatile int counter; 后的 counter++ 仍是“读-改-写”三步,三个线程同时执行就会丢更新。

  • 适合场景:状态标志(volatile boolean shutdownRequested)、双重检查锁定中的单例引用
  • 不适合场景:任何需要“读取后判断再修改”的逻辑,例如 if (count
  • 配合 AtomicInteger 使用时,volatile 是多余的——原子类内部已处理好内存语义
实际编码中最容易被绕过的,是复合操作的原子性缺失。哪怕用了 volatile 或 AtomicInteger,只要逻辑跨多步,就得回到锁或更高级同步工具。这不是语法问题,而是对“共享状态变更边界”的理解是否到位。

热门AI工具

更多
WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

相关专题

更多
java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

2090

2023.11.13

java boolean类型
java boolean类型

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

143

2025.11.30

counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2568

2023.11.20

counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2568

2023.11.20

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

5439

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2745

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

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

3388

2025.08.29

C++中int的含义
C++中int的含义

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

2445

2025.08.29

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

0

2026.09.30

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn