synchronized 与 volatile 关键字
目录
- 1.前言
- 1.synchronized 关键字
- 1. 互斥
- 2.保证内存可见性
- 3.可重入
- 2. volatile 关键字
- 1.保证内存可见性
- 2.无法保证原子性
- 3.synchronized 与 volatile 的区别
1.前言
synchronized关键字和volatile是大家在Java多线程学习时接触的两个关键字,很多同学可能学习完就忘记了,本文帮助大家回顾以及学习两个关键字的作用,以及说出它们的区别,同时也为了自己学习巩固。
1.synchronized 关键字
1. 互斥
属于synchronized最关键的特性,可以起到互斥的作用,当某个线程执行到某个对象的synchronized中时,其他线程如果也执行到同一个对象 的synchronized 时就会进行阻塞等待。
- 进入
synchronized修饰的代码块此时相当于 加锁 - 退出
synchronized修饰的代码块此时相当于 释放锁
其解决的问题是在多线程环境下,多个线程对于同一个变量进行读写操作时可能产生的线程安全问题。
如下图代码:
public class Main {static int count = 0;static void add() {count++;}public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {add();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {add();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}
}
按照预期,我们希望count的值应该是100000,当执行后输出的答案却是:

无论多次执行多少次,答案总是与预期相差甚远。这是最简单的多线程安全问题。因为count++这个操作,需要先将count从主内存读入到工作内存,然后增值,再将更改后的值写回主内存,这一系列操作必须保证原子性,而在多线程环境下是无法保证的,所以我们需要加上synchronized进行上锁,以此保证自增这个操作的原子性。
只需更改add方法如下:
synchronized static void add() {count++;}
再次运行后答案与预期相符合:

需要注意一点,synchronized修饰方法时如果是静态方法,则加的是该类对象的锁,如果是成员方法,则加的是对象锁。
2.保证内存可见性
从上面也可以看出synchronized的工作过程:
- 1.获得互斥锁
- 2.从主内存拷贝变量的最新副本到工作内存
- 3.执行代码
- 4.讲更改后的共享变量的值更新回工作内存
- 5.释放互斥锁
这样的工作流程,是一定可以保证内存可见性的。当然有的同学并不了解什么是内存可见性,下文讲volatile时我们稍微讲一下,因为它也能保证内存可见性。
3.可重入
synchronized同步块,对于同一条线程来说是可重入的,不会出现将自身锁死的情况。
当然大家可能对 自身锁死 这个情况不太理解,我们举例一个代码:
public class Main {//锁对象public static Object lock = new Object();public static void main(String[] args) {//一次加锁synchronized (lock) {//二次加锁synchronized (lock) {System.out.println("正确输出");}}}
}
当线程在一次加锁时,会成功加锁,当第二次加锁时,此时lock已被上锁,于是该线程进行阻塞等待,但其实这个锁是被它自己拿着的,它又不进行释放锁操作,于是将自己锁死。这样的锁称之为 不可重入锁。
当我们Java中的synchronized是可重入锁,不会出现上面的问题,它可以正确打印:

如果对上述代码还不够理解,可以再看一个二次加锁的例子:
public class Main {public int count = 0;synchronized void increase() {count++;}synchronized void increase2() {increase();}
}
在上诉代码中:
increase和increase2两个方法都加了synchronized,而且它们的锁对象都是针对当前对象加锁的。- 在调用
increase2时,会先给该对象上锁,执行调用increase时,会二次上锁(此时上个锁还未释放),这是没问题的,因为synchronized是可重入锁。
那是否真的上了两把锁呢?
其实并非如此,在可重入锁的内部,包含了 线程持有者 和 计数器 两个信息。
- 如果某个线程加锁时,发现锁已被占用,但又发现占用的恰好是自己时,那么然后可以获取到这个锁,并让计数器自增
- 解锁时首先会让计数器自减,但只有真正自减到
0时,我们才会真正意义上的将该锁释放,以供其他线程获取到。
2. volatile 关键字
相对于 synchronized来说,大家可能对volatile会比较陌生,我们来看看其有哪些作用。
1.保证内存可见性

简单来说,线程在工作时,会去主内存中读取数据到工作内存中,然后从工作内存读取数据。但是,线程从工作内存读取数据的速度,要远远的大于从主内存读取数据。
当一个线程大量地从主内存请求同一个变量的值时,它会发现这个值一直没变,此时jvm会 “自作主张” 的进行优化,直接从工作内存读取之前读到的值。这就会导致一个问题,其他线程对这个共享变量值进行修改,这个线程不能及时地被看到,也就读到了一个错误的值。
比如如下代码:
public class Main{static int isQuit = 0;public static void main(String[] args) {Thread t = new Thread(() -> {while (isQuit == 0) {}System.out.println("t线程执行结束");});t.start();Scanner sc = new Scanner(System.in);isQuit = sc.nextInt();System.out.println("main线程执行结束");}
}
执行以后随便输入一个非零整数:

发现t线程仍然在进行,而main线程已经结束,但按照逻辑其实此时isQuit值被修改为非零,t线程也应该结束。这就是由于内存可见性产生的问题,main线程修改了isQuit的值t线程并不能及时的接收到。
解决的方法也很简单,只需要给isQuit加上volatile关键字,这样每次t线程都会强制去主内存中读取isQuit的值,从而保证了内存可见性。
2.无法保证原子性
volatile相较于synchronized来说,主要在于其无法保证原子性,也就是对于下面这个程序,即使给count加上volatile,我们也无法让count的值为100000。
public class Main {static int count = 0;static void add() {count++;}public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {add();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {add();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}
}
3.synchronized 与 volatile 的区别
根据上面的总结,我们可知:synchronized既可以保证原子性还可以保证内存可见性,而volatile只能保证内存可见性。那有的人是不是肯定想,那我们无脑使用synchronized不就好了吗?
那肯定不对,synchronized会进行加锁,使得效率大大的较低,而volatile却不会影响效率,所以只有必须要保证原子性的操作,我们才选择synchronized进行加锁。
相关文章:
synchronized 与 volatile 关键字
目录1.前言1.synchronized 关键字1. 互斥2.保证内存可见性3.可重入2. volatile 关键字1.保证内存可见性2.无法保证原子性3.synchronized 与 volatile 的区别1.前言 synchronized关键字和volatile是大家在Java多线程学习时接触的两个关键字,很多同学可能学习完就忘记…...
【0成本搭建个人博客】——Hexo+Node.js+Gitee Pages
目录 1、下载安装Git 2、下载安装Node.js 3、使用Hexo进行博客的搭建 4、更改博客样式 5、将博客上传到Gitee 6、更新博客 首先看一下Hexo的博客的效果。 1、下载安装Git Git 是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本…...
【面试实战】认证授权流程及原理分析
认证授权流程及原理分析 1、认证 (Authentication) 和授权 (Authorization)的区别是什么?2、什么是Cookie ? Cookie的作用是什么?如何在服务端使用 Cookie ?3、Cookie 和 Session 有什么区别?如何使用Session进行身份验证?1、认证 (Authentication) 和授权 (Authorizatio…...
TPM命令解析之tpm2_startauthsession
参考网址链接:tpm2-tools/tpm2_startauthsession.1.md at master tpm2-software/tpm2-tools GitHub 命令名称 tpm2_startauthsession 功能 启动一个TPM会话。 命令形式 tpm2_startauthsession [OPTIONS] 描述 启动一个TPM会话。默认是启动一个试验(…...
第14章 局部波动率模型
这学期会时不时更新一下伊曼纽尔德曼(Emanuel Derman) 教授与迈克尔B.米勒(Michael B. Miller)的《The Volatility Smile》这本书,本意是协助导师课程需要,发在这里有意的朋友们可以学习一下,思…...
云原生周刊:开源“赢了”,但它可持续吗?
日前召开的 State of Open 会议上,开源“赢了”,但如果政府和企业不站出来确保生态系统在未来的弹性和可持续性,那么它仍然会失败。 OpenUK 首席执行官 Amanda Brock 在开幕式上表示,数字化和开源在过去 5 到 10 年的进步提升了工…...
读《企业IT架构转型之道》
本书还没读完,暂摘抄一些概念,因为自身做的新系统也在转型,从单体式到一体化一年来遇到很多问题有技术上的,也有团队协作的,过程是痛苦且复杂的,所以在刚翻阅前几十页时候,对于淘宝技术团队转型…...
Qt中的QTcpSocket、QWebSocket和QLocalSocket
同时实现了QTcpSocket、QWebSocket和QLocalSocket的简单通讯deamon,支持自动获取本机ip,多个客户端交互。在这个基础上你可以自己加错误检测、心跳发送、包封装解析和客户端自动重连等功能。 获取本机电脑ip: QString Widget::getIp() {QSt…...
枚举学习贴
1. 概述 1.1 是什么 枚举对应英文(enumeration, 简写 enum)枚举是一组常量的集合。可以这里理解:枚举属于一种特殊的类,里面只包含一组有限的特定的对象 1.2 枚举的二种实现方式 自定义类实现枚举使用 enum 关键字实现枚举 1.3 什么时候用 存在有限…...
【C++】30h速成C++从入门到精通(继承)
继承的概念及定义继承的概念继承(inheritance)机制是面向对象程序设计使代码可以复用的重要手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序…...
Java多线程还不会的进来吧,为你量身打造
💗推荐阅读文章💗 🌸JavaSE系列🌸👉1️⃣《JavaSE系列教程》🌺MySQL系列🌺👉2️⃣《MySQL系列教程》🍀JavaWeb系列🍀👉3️⃣《JavaWeb系列教程》…...
8 神经网络及Python实现
1 人工神经网络的历史 1.1 生物模型 1943年,心理学家W.S.McCulloch和数理逻辑学家W.Pitts基于神经元的生理特征,建立了单个神经元的数学模型(MP模型)。 1.2 数学模型 ykφ(∑i1mωkixibk)φ(WkTXb)y_{k}\varphi\left(\sum_{i1…...
使用QIS(Quantum Image Sensor)图像重建总结(1)
最近看了不少使用QIS重建图像的文章,觉得比较完整详细的还是Abhiram Gnanasambandam的博士论文:https://hammer.purdue.edu/articles/thesis/Computer_vision_at_low_light/20057081 1 介绍 讲述了又墨子的小孔成像原理,到交卷相机…...
【SpringCloud】SpringCloud教程之Nacos实战(二)
目录前言一.Nacos实现配置管理二.Nacos拉取配置三.Nacos配置热更新(自动刷新,不需要重启服务)1.在有Value注入变量所在类添加注解2.新建类用于属性加载和配置热更新四.Nacos多环境配置共享1.多环境共享配置2.配置的加载优先级测试3.配置优先级前言 Nacos实战一&…...
利用Qemu工具仿真ARM64平台
Windows系统利用Qemu仿真ARM64平台0 写在最前1 Windows安装Qemu1.1 下载Qemu1.2 安装Qemu1.3 添加环境变量1.4测试安装是否成功2. Qemu安装Ubuntu-Server-Arm-642.1 安装前的准备2.2 安装Ubuntu server arm 64位镜像3 Windows配置Qemu网络和传输文件3.1 参考内容3.2 Windows安装…...
【Hello Linux】进程控制 (内含思维导图)
作者:小萌新 专栏:Linux 作者简介:大二学生 希望能和大家一起进步! 本篇博客简介:简单介绍下进程的控制 包括进程启动 进程终止 进程等待 进程替换等概念 进程控制介绍进程创建fork函数fork函数的返回值fork函数的使用…...
嵌入式linux物联网毕业设计项目智能语音识别基于stm32mp157开发板
stm32mp157开发板FS-MP1A是华清远见自主研发的一款高品质、高性价比的Linux单片机二合一的嵌入式教学级开发板。开发板搭载ST的STM32MP157高性能微处理器,集成2个Cortex-A7核和1个Cortex-M4 核,A7核上可以跑Linux操作系统,M4核上可以跑FreeRT…...
【黄河流域公安院校网络空间安全技能挑战赛】部分wp
文章目录webbabyPHPfunnyPHPEzphp**遍历文件目录的类**1、DirectoryIterator:2、FilesystemIterator:3、**Globlterator**读取文件内容的类:SplFileObjectMisc套娃web babyPHP <?php highlight_file(__FILE__); error_reporting(0);$num $_GET[nu…...
五点CRM系统核心功能是什么
很多企业已经把CRM客户管理系统纳入信息化建设首选,用于提升核心竞争力,改善企业市场、销售、服务、渠道和客户管理等几个方面,并进行创新或转型。CRM系统战略的五个关键要点是:挖掘潜在客户、评估和培育、跟进并成交、分析并提高…...
window.print() 前端实现网页打印详解
目录 前言 一、print()方法 二、打印样式 2.1使用打印样式表 2.2使用媒介查询 2.3内联样式使用media属性 2.4在css中使用import引入打印样式表 三、打印指定区域部分内容 3.1方法一 3.2方法二 3.3方法三 四、强制插入分页 4.1page-break-before(指定元素前…...
Spring Boot Helper插件免费版获取与版本适配全攻略
1. 为什么我们需要Spring Boot Helper插件 作为一个常年使用IntelliJ IDEA开发Spring Boot项目的程序员,我深刻体会到这个插件的重要性。简单来说,它就像是Spring Boot开发的"瑞士军刀",能帮我们快速创建项目、自动配置依赖、一键…...
LWIP内存管理踩坑实录:从pbuf泄漏到pcb耗尽,我的嵌入式网络调试日记
LWIP内存管理踩坑实录:从pbuf泄漏到pcb耗尽,我的嵌入式网络调试日记 凌晨三点,调试器上的红色LED还在闪烁。这是我连续第三个通宵追踪LWIP的内存问题——设备在运行48小时后必然崩溃,日志里满是"pbuf_alloc failed"和&q…...
解锁Switch模拟潜能:Ryujinx架构深度解析与实战优化
解锁Switch模拟潜能:Ryujinx架构深度解析与实战优化 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx Ryujinx作为一款采用C#开发的开源Nintendo Switch模拟器,通…...
开源编解码工具技术选型与实战指南:跨场景应用的H.264解决方案
开源编解码工具技术选型与实战指南:跨场景应用的H.264解决方案 【免费下载链接】openh264 Open Source H.264 Codec 项目地址: https://gitcode.com/gh_mirrors/op/openh264 一、价值定位:为什么开源编解码工具是技术选型的最优解 在视频技术快…...
TikTok零/低播放突围:跨境账号实战破局指南
图片来源:TK云大师0播放或低播放是TikTok跨境从业者的高频痛点——行业数据显示,超68%新手账号遇初始零播放,45%带货账号因持续低播放停摆。耗时制作的内容无人问津,既耗资源又乱节奏。结合实操经验,本文从排查、挽救、…...
OpenClaw 全面解析:Token时代的iPhone如何颠覆开发者工作流?
前言:两周15万Star背后的技术革命 2026年初,一个名为 OpenClaw 的开源项目在 GitHub 上以惊人速度走红——两周内突破 15 万 Star,如今已达 310k Star,成为近年来增速最快的开源项目之一。 黄仁勋在最新访谈中将其称为 “Token时代…...
【紧急预警】Mojo nightly build已悄然移除PyModule::import() API!立即备份旧版+迁移至PyO3 0.21+手动GC管理方案(附自动化迁移脚本)
第一章:【紧急预警】Mojo nightly build已悄然移除PyModule::import() API!立即备份旧版迁移至PyO3 0.21手动GC管理方案(附自动化迁移脚本)Mojo nightly build v2024.06.12 起,PyModule::import() 已被彻底移除&#x…...
Linux下RTL8188无线网卡变身AP热点:从驱动安装到自动分配IP全流程(附避坑指南)
Linux下RTL8188无线网卡配置AP热点全攻略:从驱动到自动IP分配的实战指南 在嵌入式开发和物联网应用中,将无线网卡配置为接入点(AP)是常见需求。RTL8188系列USB无线网卡因其高性价比和广泛兼容性,成为开发者的热门选择。…...
Multisim电路设计避坑指南:红绿灯项目里那些容易忽略的时序与驱动问题
Multisim电路设计避坑指南:红绿灯项目里那些容易忽略的时序与驱动问题 当你第一次在Multisim中完成红绿灯控制电路的设计时,那种成就感确实令人兴奋。但很快,你可能就会遇到一些令人头疼的问题:黄灯闪烁频率不稳定、倒计时显示乱跳…...
资源监控告警:OpenClaw+Qwen3-32B镜像守护个人服务器
资源监控告警:OpenClawQwen3-32B镜像守护个人服务器 1. 为什么需要智能化的个人服务器监控? 去年我的个人服务器连续宕机三次——第一次因为内存泄漏导致OOM崩溃,第二次被挖矿程序占用全部CPU资源,第三次则是磁盘写满后无人察觉…...
