深入理解 Java 中的 volatile 和 synchronized 关键字

Java中的volatile与synchronized 简介 Java中多线程并发编程中synchronized和volatile是对于线程的安全保证的两个重要机制;简单来说synchronized提供了一种独占加锁的机制,使得当前锁住的对象只被一个线程访问;volatile用于保证了线程的在共享内存中变量对于所有线程可见与禁止cpu指令重排作用;从而保证部分状态下的线程安全; 线程安全的三大特性: 原子性:一组语句作为一个不可分割的单元被执行。 可见性:修改一个共享变量时,其他线程可以读到这个修改的值; 有序性:对于多个线程执行来说,他们之间必须是相对有序的; 阅读详情

在多线程编程中,Java 提供了 volatile 和 synchronized 两种关键字来管理线程之间的交互。它们各自具有独特的特性,可以解决不同类型的并发问题。本文将结合两者的特点,深入探讨它们的用法、工作原理及实际开发中的应用场景。


什么是 volatile?

volatile 是一种轻量级的同步机制,用于确保变量的可见性和防止指令重排序。它主要解决以下两大问题:

  1. 可见性
    当一个线程修改了 volatile 变量的值,其他线程会立即感知到这一变化。

  2. 防止指令重排序
    通过 volatile 修饰的变量,编译器和处理器不会对其相关指令进行重排序优化。

示例代码

以下代码展示了 volatile 的一个典型使用场景:

public class VolatileExample {
    private static volatile boolean flag = false;

    public static void main(String[] args) {
        new Thread(() -> {
            System.out.println("Thread 1: 正在等待 flag 变为 true...");
            while (!flag) {
                // 循环等待
            }
            System.out.println("Thread 1: 结束等待,flag 已变为 true!");
        }).start();

        new Thread(() -> {
            try {
                Thread.sleep(2000); // 模拟延迟
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            flag = true;
            System.out.println("Thread 2: 已将 flag 设置为 true.");
        }).start();
    }
}

在这段代码中,Thread 1 能够及时感知到 flag 的改变,是因为 flag 被声明为 volatile,避免了线程缓存带来的数据可见性问题。

volatile 的局限性

  1. 无法保证原子性
    对于复合操作(如 count++),volatile 不能确保线程安全。

  2. 不支持锁机制
    volatile 仅能保证可见性,无法实现对共享资源的互斥访问。


什么是 synchronized?

synchronized 是 Java 提供的一种重量级同步机制,用于控制线程对共享资源的访问。它不仅可以确保可见性,还可以保证操作的原子性。

Synchronized 的用法

synchronized 可以用在方法上,也可以用在代码块中。

同步方法
public synchronized void incrementCount() {
    count++;
}

使用同步方法时,整个方法被锁定,保证在同一时间只有一个线程可以执行该方法。

同步代码块
public void incrementCount() {
    synchronized (this) {
        count++;
    }
}

同步代码块允许对特定的代码段进行同步,而非锁定整个方法,这样可以提高效率。


volatile 与 synchronized 的对比

特性volatilesynchronized
可见性保证保证
原子性不保证保证
重排序防止指令重排序默认防止
性能开销较低较高,线程可能需要进入阻塞状态
适用场景状态标识或简单变量复杂逻辑或涉及多步操作的场景

结合使用 volatile 和 synchronized

在某些场景下,可以结合使用 volatile 和 synchronized,以便在提供线程安全的同时降低性能开销。例如,在单例模式的双重检查锁(DCL)中,volatile 和 synchronized 的组合是经典用法:

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

在这段代码中:

  • volatile 保证 instance 的可见性,防止指令重排序。
  • synchronized 确保实例化过程的线程安全。

总结

  • volatile 是一种轻量级的同步机制,适用于标志位或简单变量的更新场景。
  • synchronized 提供了更强的同步能力,适用于复杂的多步操作,但可能带来性能开销。
  • 两者各有优缺点,可以结合实际需求选择使用,甚至在某些情况下可以配合使用。

通过正确理解和使用 volatile 和 synchronized,开发者可以更高效地编写多线程程序,既保障线程安全,又兼顾性能优化。这是 Java 并发编程中的重要一环,也是深入掌握多线程技术的关键步骤。

参考链接

深入理解 Java 中的 Synchronized 关键字

深入理解 Java 中的 volatile 关键字

从波形到代码:手把手调试GaN图腾柱PFC的过零点切换与软启动策略 本文详细解析了GaN图腾柱无桥Boost PFC电路在过零点切换与软启动策略中的调试方法。通过波形分析、代码实现和寄存器配置,提供了解决误开通、震荡波形等问题的实用方案,帮助工程师优化电源设计效率与可靠性。 阅读详情

相关推荐

AD9361 官方例程

文章目录一、官方资料1.1 介绍1.2 下载 和 使用1.3 相关资料二、步骤2.1 在Vivado中构建HDL2.2 在SDK中构建No- OS总结 一、官方资料 1.1 介绍 HDL参考设计介绍:AD9361 HDL Reference Designs 无操作系统介绍:AD9361 No-OS Software 1.2 下载 和 使用 HDL下载:Download HDL 在Vivado中构建HDL:Building HDL No-OS下载:Download No-OS 1.3 相关资料 AD

weixin_44630490的博客 3万+

Java锁(一):volatile、synchronized详解

一、锁的基础知识 锁的类型 锁从客观上分为悲观锁和乐观锁。 乐观锁:乐观锁是一种乐观思想,认为写少读多,遇到并发写的可能性比较低,读数据的时候认为别人不会修改,所以读的时候不会上锁,但是在写的时候会判断一下在此期间有没有别人去更新这个数据,采取的是先读取当前版本号,然后加锁操作,写完的时候读取最新版本号做记录的版本号做比较一样则成功,如果失败则重复读-比较-写的操作。Java中的乐观锁基本都是通过CAS操作实现的,java.util.concurrent.atomic包下的原子变量。CAS(compare

qq_34222160的博客 2629

生信人的一天~HIFI数据+HIC数据组装基因组

HIFI+HIC数据组装基因组!

qq_43337286的博客 9530

Java 并发(四)—— volatile 和 synchronized

如果我们将一个变量使用volatile修饰,这就指示 编译器,这个变量是共享且不稳定的,。

weixin_68074170的博客 1021

千兆以太网PHY设计:PCB原理图完整示例

深入解析千兆以太网PHY电路设计要点,提供完整的PCB原理图设计实例,帮助工程师掌握高速信号布局与电源去耦等关键技术,提升设计稳定性与信号完整性。

weixin_30633869的博客 628

关于使用vcpkg下载osgearth遇到的问题

注意--x-manifest-root=后面跟着的E:\gitproject\osgearth-osgearth-3.5\vcpkg是你下载的源码解压缩后vcpkg.json的文件地址,然后等待编译完成。安装vcpkg后使用vcpkg install osgearth:x64-windows安装好osgearth并且导入项目使用时,发现无法运行官方文档中示例的main.cpp。这里写一种自己用过的使用vcpkg安装osgearth3.5的方法,源码,打开vcpkg所在的命令行,执行。示例main.cpp。

m0_61776040的博客 1523

Java之volatile的作用 && volatile与synchronized的区别

为了提高程序的运行效率,编译器会自动对其进行优化,把经常被访问的变量缓存起来,程序在读取这个变量时会直接从缓存中读取,而不会从内存中读取 当遇到多线程时,变量的值可能因为别的线程而改变,而缓存的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致 volatile是用来修饰被不同线程访问和修改的变量 被volatile修饰的变量,系统每次用到它时都是直接从对应的内存中提取,而不会利用缓存 ...

NO_BUG_GIRL的博客 284

从CMOS到CML:手把手教你为PLL选对分频器电路(附性能对比与选型指南)

本文深入解析了PLL分频器电路的三大主流架构——静态CMOS、动态TSPC和CML,通过性能参数对比和实测数据,提供了从频率需求、功耗预算到噪声防护的完整选型指南。特别针对高频应用的CML分频器设计要点和混合架构优化方案,为射频与模拟IC设计工程师提供实用参考。

weixin_30887919的博客 457

Java并发编程——volatile和synchronize详解

volatile 可见性,是否具备原子性、原理介绍,synchronized使用方法、原理、锁升级过程介绍

共勉 1014

AI Agent核心架构解析:从Tool、Skill到MCP协议的智能体构建实战

在人工智能领域,大语言模型(LLM)赋予了AI自主规划与决策的能力,推动了智能体(Agent)技术的演进。其核心原理在于构建一个具备感知、规划、行动与反思能力的自主系统。这一架构的技术价值在于将AI从被动应答升级为主动执行复杂任务的工作伙伴,显著提升了自动化水平与问题解决效率。应用场景广泛覆盖了市场分析、自动化办公、智能客服与垂直领域集成等。本文聚焦于实现这一能力的关键组件:基础工具(Tool)、组合技能(Skill)与标准化协议(MCP)。其中,Skill通过封装多个Tool形成可复用的高级能力,而MCP

chuannaoxuan4674的博客 318

手把手教你用NetToPLCsim搭建西门子S7-1200仿真环境(附避坑指南)

本文详细指导如何利用NetToPLCsim与PLCSIM搭建西门子S7-1200仿真环境,实现无硬件条件下的PLC程序测试与上位机通信开发。内容涵盖软件选型、环境部署、关键参数配置及通信测试,并重点提供了连接失败、数据读写错误等常见问题的深度避坑指南,帮助工程师高效构建可靠的虚拟调试工作流。

a3b4c5的博客 611

Java 并发编程基石:深入理解 synchronized 与 volatile 关键字

提供轻量级的可见性保证和禁止重排序,但不提供原子性。开发者必须深刻理解它们的工作原理、差异和适用场景,才能在并发编程中做出正确的选择,构建出线程安全、高效可靠的应用程序。理解它们的原理、差异和适用场景,是掌握 Java 并发编程的关键一步。希望这篇技术文章能帮助您更好地理解 Java 并发编程中的这两个核心概念。是 Java 提供的最基础的互斥同步机制。是 Java 并发编程中解决共享数据访问问题的两大基石。提供互斥性和原子性,并附带可见性保证,但开销相对较大。是深入学习 Java 并发编程的必经之路。

2601_95053010的博客 999

ANSYS WORKBENCH——参数化建模以及参数优化(结果导出为Excel)

目录 1、打开软件workbench 2、找到static structure,双击打开 3、选择材料 4、参数化建模 ​ 注:印记面的创建 5、模型属性设置 注:设置优化目标 6、回主界面,选择direct optimization模块 1、打开软件workbench 2、找到static structure,双击打开 3、选择材料 4、参数化建模 至此参数化建模就已经完成啦 注:印记面的创建 印记面一般是一个虚拟的区域,参与实际的网格划分,但是只是由于载.

python_AI_fans的博客 1万+

深入理解JAVA多线程---对象及变量的并发访问(synchronized和volatile关键字)

synchronized和volatile关键字前言线程不安全问题解决线程不安全问题synchronized实现原理volatile 前言 在多线程开发过程中,难免遇到很多线程不安全的问题,例如多个线程对一个变量进行访问和修改,就会产生"脏读".因此利用好synchronized和volatile关键字是多线程的关键一步. 线程不安全问题 首先我们来看一段线程不安全的代码: public class synchronizedAndVolatile { public static int i = 0;

莫秃 286

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

JAVA基础面试题:深入理解synchronized与volatile关键字在多线程环境下的性能优化策略

和volatile是Java多线程编程的核心关键字,理解其原理和适用场景是优化性能的关键。在实际开发中,应根据具体需求选择合适的同步机制,并结合性能优化策略提升系统吞吐量。

Victor_119的博客 427

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Java中的特殊关键字

说他特殊,是因为C++中没有或意思有变化: final: final修饰的类,和方法都很好理解。 关键是final修饰的函数变量,如void pro(final String str); final 关键字保证对被final修饰的变量只能赋值一次,也就是说final不能再指向别的变量了。但是被指的这个变量还是可以改变的。 使用final修饰符不仅会保持对象不会改变,而且编译器还会

chjjunking的专栏 1003

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

《Java并发编程的艺术》——Volatile关键字与Synchronized关键字

Java并发编程的艺术Volatile关键字的原理Volatile关键字的内存语义单例模式下的双重锁为什么要volatile?volatile关键字不适合用于i++操作的原因:Synchronized关键字锁升级的过程 Volatile关键字的原理 提到volatile关键字, 就不得不提两个关键词: JMM内存模型:JMM定义了线程和主内存之间的抽象关系:共享变量存储在主内存(Main Memory)中,而每个线程都有一个私有的内部缓存(Local Memory),内部缓存保存了被该线程使用到的变量的主内

Squid87的博客 423

一文搞懂Volatile关键字的作用

一文搞懂Volatile关键字的作用

程序媛小琬的博客 682

JAVA关键字

1. 请你讲讲Java里面的final关键字是怎么用的? 答:当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。 “使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用

m0_48028855的博客 102

Java 常用关键字总结(基础)

java 常用关键字staticfinalfinal 属性final 方法final 参数final 类transienttransient 使用小结volatile(保证可见性、有序性,不保证操作的原子性) static static,静态,表示随着类的加载而加载,不会重复加载,执行顺序在 main 方法之前。在 JVM 内存里,static 修饰的变量存在于方法区中。 final final 用于声明属性、方法和类,分别表示属性不可变,方法不可覆盖,类不可被继承(不能再派生出新的子类)。 final 属

weixin_37603663的博客 616

JAVA多线程之volatile 与 synchronized 的比较

一,volatile关键字的可见性要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下:从图中可以看出:①每个线程都有一个自己的本地内存空间--线程栈空间???线程执行时,先把变量从主内存读取到线程自己的本地内存空间,然后再对该变量进行操作②对该变量操作完后,在某个时间再把变量刷新回主内存volatile常用于修饰变量,且该变量能够在不同线程间共享,保证每...

AlexQiweek的博客 326

并发编程——Volatile关键字

volatile概述 简单的cpu内存模型 三大特性 volatile的原理,应用以及volatile与synchronized的对比

u014112521的专栏 591

关键字

● 请你讲讲Java里面的final关键字是怎么用的? 考察点:关键字 参考回答: 当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。 “使用final方法的原因有两个。第一个原因是把方法锁定,以防...

weixin_30273175的博客 134

结合Java内存模型理解synchronized、volatile和final关键字

在面试时,经常问到Java内存模型以及synchronized、volatile和final关键字。实际上他们是可以相互影响的两个知识点。 目录 一、Java内存模型 1.1 硬件的效率和一致性 1.2 工作内存与主内存 1.3 内存之间的交互操作 1.4 重排序 二、结合内存模型理解三个关键字   一、Java内存模型 参考资料:残雪余香-Java内存模型 1.1 硬件的效...

m0_37860933的博客 808

volatile和synchronized的区别

volatile和synchronized特点 首先需要理解线程安全的两个方面:执行控制和内存可见。 执行控制的目的是控制代码执行(顺序)及是否可以并发执行。 内存可见控制的是线程执行结果在内存中对其它线程的可见性。根据Java内存模型的实现,线程在具体执行时,会先拷贝主存数据到线程本地(CPU缓存),操作完成后再把结果从线程本地刷到主存。 synchronized关键字解决的是执行控制的...

weixin_30273501的博客 67

Java synchronized 能防止指令重排序吗?为何双重校验单例模式要加上 volatile?

一、synchronized 的有序性 Java 里的操作无序现象是什么? 《深入理解 Java 虚拟机》- P374: 如果在一个线程观察另一个线程,所有操作都是无序的指的是 “指令重排序” 和 “工作内存与主内存同步延迟” 现象。 指令重排是JVM层面对程序进行的优化措施,如果不深入了解,则在并发编程时可能会发生难以发现的Bug。 截止JDK1.8, Java 里只有 volatile 变量是能实现禁止指令重排的。 synchronized 虽不能禁止指令重排,但能保证有序性 这个有序性是

书生不读四书五经 1033
上一篇: 深入理解C语言指针:从基础到进阶
下一篇: 使用 Vue 与 WebSocket 实现实时通信
codingexpert404
博客等级 码龄2年 196粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值