JAVA多线程基础篇 5、原子性与锁

Java多线程:线程操作的原子性问题 概述 : 原子性是指在一次操作或者多次操作中,要么所有的操作全部都得到了执行并且不会受到任何因素的干扰而中断,要么所有的操作都不执行,多个操作是一个不可以分割的整体。例如一个送冰淇淋的案例:开启100条线程,每个线程送100个冰淇淋。代码实现 : 运行结果如下: 从结果看出,最后不是10000个冰淇淋,有些count++操作被“打断”了。代码总结 : count++ 不是一个原子性操作, 他在执行的过程中,有可能被其他线程打断,并且说明 volatile关键字不能保证原子性解决方案 : 我们可以给coun 阅读详情

1. 竞态条件

在并发编程中,多线程会抢占运行各自的代码片段,当访问共享数据时会产生不正确的结果。

public class ConditionRaceExp {

    private static volatile int counter = 0;

    public static void main(String[] args) throws InterruptedException {

        Thread[] threads = new Thread[1000];

        for(int i=0;i<1000;i++){
            threads[i] = new Thread(()->{
                for(int k=0;k<10000;k++)
                    counter++;
            });
        }

        for(int i=0;i<1000;i++){
            threads[i].start();
        }

        for(int i=0;i<1000;i++){
            threads[i].join();
        }
        System.out.println(counter);
    }
}

预期结果应该是1000000,但实际运行结果与预期不符。

conditionrace

原因是因为在执行counter++时,等同于counter = counter+1,在多线程环境中这句命令会被打断,比如A线程在执行该语句时,counter瞬时的值为100,A线程执行counter+1,得到值为101,在赋值回counter时,问题发生了——B、C、D线程抢占了CPU资源,并将counter值加到了103,等A线程回到CPU运行的时候,又会把101赋值给counter。 此种情况被成为竞态条件。

2. 原子性

要让程序能得到预期的结果,需要让涉及到竞态条件的程序指令的原子性不被破坏。此时需要将程序进行保护。JAVA提供了锁机制来保护程序,根策略不同可以分为悲观锁和乐观锁两种。

2.1 悲观锁

首先需要定义一个对象,锁是上在某个普通对象上的,也可以是某个class对象上。上锁的过程其实就是在对象头上更改状态位、以及写入自己的信息。如果没有指明,则根据方法来判定,如果是实例方法,则锁在this对象上。如果是静态方法,则锁在这个实例所在的类对象上。

Java调用锁有多种方法,一般使用synchronized方法对象。

tips:在发生异常后,线程会自己释放锁的。

Object o = new Object();
synchronized(o){
    //此时,这把锁上在 o 这个对象上
}

synchronized(T.class){
    //此时,是上锁在T.class 这个对象,这个对象是Class类型的,是类加载的虚拟机后创建的。
}

2.2 乐观锁

乐观锁的实现是CAS(Compare and Swap)算法,CAS算法并没有真正“锁定”内存的对象,也被称为无锁算法。
CAS底层原理是,CAS在为对象赋值的时候,会带上对象的预期的值,将预期值和当前值进行比较(Compare),如果是一致的,就进行赋值(Swap)。否则继续重试,因此也称为自旋锁。CAS存在ABA的问题,一般是通过版本号或时间戳加上数据进行双重检验。
CAS在底层是由操作系统保证的,操作系统会调用指令 lock cmpxchg 对缓存行或总线加锁,保证原子性。

2.3 两种锁的比较

尽管悲观锁需要对锁资源进行抢占和排队,但是排队时线程并不占据CPU资源;而乐观锁的线程都会持续自旋(循环轮询)占用CPU的时间片段,因此根据线程并发数和实际测试情况,才能判断那种锁的效率高。

3.加锁的方法

  • 使用synchronized关键字
  • 使用ReentrantLock对象
  • 使用JUC库的各种工具类(详见进阶篇)

总结

锁能保证原子性。但是并不代表上锁就一定安全,程序的设计需要考虑周到。锁分为乐观锁和悲观锁,悲观锁基于对象头锁定,乐观锁基于CAS算法。对于并发数少、执行时间比较短的情况,建议使用CAS;否则建议使用悲观锁。

多线程系列在github上有一个开源项目,主要是本系列博客的实验代码。

https://github.com/forestnlp/concurrentlab

如果您对软件开发、机器学习、深度学习有兴趣请关注本博客,将持续推出Java、软件架构、深度学习相关专栏。

您的支持是对我最大的鼓励。

MacBook 本地化部署 Dify 指南 dify 怎么安装部署 有哪些坑 ! 阅读详情

相关推荐

家用电器维修必备:手把手教你用双向可控硅改造单相电机调速(附电路图)

本文提供了一份详细的家用电器维修指南,手把手教你如何利用双向可控硅为核心元件,为单相交流电机(如风扇、排气扇)实现平滑的无级调速改造。内容涵盖核心原理、安全须知、元件选型(如BT136、DB3)、电路图解析、分步搭建教程以及常见故障排查方法,旨在帮助维修爱好者和DIY用户安全、成功地完成这一实用且富有成就感的项目。

read5的博客 837

JAVA锁:原子类

JAVA锁:原子类原子类为什么会有原子类CAS无锁模式CAS算法理解CAS(乐观锁算法)的基本假设前提常用原子类 原子类 java.util.concurrent.atomic包:原子类的小工具包,支持在单个变量上解除锁的线程安全编程 原子变量类相当于一种泛化的 volatile 变量,能够支持原子的和有条件的读-改-写操作。 AtomicInteger 表示一个int类型的值,并提供了 get 和 set 方法,这些 Volatile 类型的int变量在读取和写入上有着相同的内存语义。 它还提供了一个原子

qq_25292419的博客 438

Jenkins离线安装保姆级教程:从下载.war包到SVN+Maven项目一键部署(附避坑脚本)

本文详细介绍了Jenkins离线安装的全流程,包括.war包下载、SVN+Maven项目配置及自动化部署。特别针对内网环境提供解决方案,涵盖插件管理、开发工具链配置、构建触发器和SSH部署等关键步骤,帮助企业在网络隔离环境下实现高效持续集成。

weixin_30096975的博客 374

【JAVA-多线程并发-原子-锁机制】

程序分为两个状态,非运行状态下: 代码文本 + 资源数据运行状态下:进程。

ZERO_HOPE的博客 1090

webpack性能优化-optimization.splitChunks.chunks中的“all“、“async“和“initial“

最初,chunks(以及内部导入的模块)是通过内部 webpack 图谱中的父子关系关联的。CommonsChunkPlugin 曾被用来避免他们之间的重复依赖,但是不可能再做进一步的优化。 ——摘自 webpack 从 webpack v4 开始,移除了 CommonsChunkPlugin,取而代之的是 optimization.splitChunks。 而关于 optimization.splitChunks 中的chunks,webpack 官方文档却没有很好的进行举例解释,只说明了 async.

程序员秋风的博客 3137

​银行IT运维人必看!IT运维监控指标大全,一篇讲透

文章摘要:本文从七个维度系统阐述了IT运维指标体系,涵盖机房环境、基础设施、网络设施、数据存储、虚拟化平台、数据库中间件和应用层。作者结合20年金融行业经验,详细分析了各层级关键监控指标、正常范围及异常后果,并给出典型故障场景。重点强调现代运维需从被动响应转向主动预防,通过精细化指标管理实现系统稳定性保障。文章特别指出,在国产化与DevOps背景下,运维工作需兼顾传统架构与新兴技术,构建全方位监控体系,将运维从"故障报警"升级为"业务守护"。

最近开始研究AIGC领域技术,欢迎交流 1106

Java并发编程——原子性锁

一、同步锁 synchronized同步锁:依赖JVM来实现; 优缺点:不可中断,适合竞争不激烈的场景,可读性号; Lock:依赖特殊的CPU指令、代码来实现,如ReentrantLock 优缺点:可中断锁,多样化同步,适合竞争激烈的场景,能维持常态; 二、synchronized 常见四种用法: 修饰代码块:大括号括起的代码,作用于调用的对象; 修饰方法【同步方法】:整个方法,作用于调用的...

zjt980452483的博客 490

优化NEXYS A7开发板(Xilinx Artix-7)Microblaze核的FLASH读写性能实战

本文针对NEXYS A7开发板(Xilinx Artix-7)上Microblaze核读写FLASH速度慢的问题,提供了系统性的优化实战指南。通过深入分析SPI控制器配置、Flash指令模式选择、Microblaze核的Cache与硬件加速器优化,以及程序运行位置(BRAM vs DDR)的调整,有效将FLASH读写性能从“龟速”提升至接近理论峰值。文章结合实测数据,为FPGA嵌入式开发者提供了清晰的性能瓶颈分析与解决方案。

carrot的博客 257

JAVA并发编程(2)——(如何保证原子性,原子类,CAS乐观锁,JUC常用类)

如原先的内存值为(A,1),线程将(A,1)修改为了(B,2),再由(B,2) 修改为(A,3)。此时另一个线程使用预期值(A,1)与内存值(A,3)进行 比较,,因为被 synchronized 修饰某段代码 后,无论是单核 CPU 还是多核 CPU,只有一个线程能够执行该代码,所以一 定能保证原子操作.但是不断的自旋,会导致 CPU 的消耗,在并发量大的 时候容易导致 CPU 跑满。当且仅当预期值 A==V,将内存值 V=B,否则什么都不做。②预估值 A (比较时,从内存中再次读到的值)

qq_53677566的博客 2533

DeepSeek的训练与优化流程

DeepSeek的训练体系不仅追求极致的计算效率,更注重将物理规律、人类知识、安全伦理深度融入训练过程,其"效率-安全-可解释性"三角平衡的设计理念,为行业提供了重要参考范式。

m0_56896669的博客 1435

【QT】基于QSerialPort的跨平台串口通信实战指南

本文是一份基于Qt QSerialPort模块的跨平台串口通信实战指南。详细介绍了从硬件基础、QSerialPort核心类使用、参数配置、设备自动发现到数据异步读写和错误处理的完整流程,并通过构建一个功能齐全的串口调试助手实例,帮助开发者快速掌握在Windows、Linux和macOS系统下进行高效、稳定的串口应用开发。

a1b2c3d的博客 982

java线程原子锁

今天被问到这样一个问题,两个线程共用一个int类型的变量,怎么保证数据安全?(不可以用synchronized关键字)你知道原子锁吗?1. 例子引入public class RunThread extends Thread { private boolean isRunning = true; public boolean isRunning() { return isR

qq_36511830的博客 1057

在 ABAP CDS View 里把 Conversion Functions 用到极致:FLTP 精度、单位换算、货币换算与小数位处理的工程化实践

数据格式转换在真实项目中比业务逻辑更容易引发问题。ABAP CDS中的转换函数(如FLTP_TO_DEC、UNIT_CONVERSION、CURRENCY_CONVERSION和DECIMAL_SHIFT)可帮助在数据库层统一数据口径,避免应用层重复处理。这些函数支持数值精度治理、单位换算、货币转换和小数位调整,能显著提升报表性能并减少逻辑分散。通过将格式转换前移到数据模型层,可以确保服务层和UI层的数据一致性,同时降低接口传输错误风险。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 2351

多线程三大特性——原子性

概念 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行。原子性就是指该操作是不可再分的。 如果一个操作是原子性的,那么多线程并发的情况下,就不会出现变量被修改的情况。 比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么说这个操作是原子操作。再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作。 非原子操作都会存在线程安全问题,需要使用同步技术(sychronized)来让它变成一个原

城南孔乙己的专栏 5495

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Java多线程——如何保证原子性

Java多线程——如何保证原子性。

Arya的博客,专注后端领域 1777

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Java多线程 - 锁

Java多线程 - 锁 三性 可见性 指的是线程之间的可见性,一个线程对状态的修改,对其他线程是可见的。在 Java中 volatile、synchronized 和 final 实现可见性。 原子性 如果一个操作是不可分割的,我们则称之为原子操作,也就是有原子性。比如i++,就不是原子操作。在Java 中 synchronized和在lock、unlock 中操作保证原子性 有序性 一系列操作是按照规定的顺序发生的。如果在本线程之内观察,所有的操作都是有序的,如果在其他线程观察,所有的操作都是

GuoXuan_CHN的博客 6889

Java Web基础篇之Java多线程

1、多线程与进程 1.1、是什么? 线程有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元,进程与线程区别如下:一个进程至少有一个线程.。 1.2、扩展: 进程与线程区别,线程的划分尺度小于进程,使得多线程程序的并发性高。 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 线程在执行过程中与进程还是有区别的。每...

聚沙成塔 5777

多线程并发 (三) 锁 synchronized、volatile

章节:多线程并发 (一) 了解 Java 虚拟机 - JVM多线程并发 (二) 了解 Thread多线程并发 (三) 锁 synchronized、volatile多线程并发 (四) 了解原子类 AtomicXX 属性地址偏移量,CAS机制多线程并发 (五) ReentrantLock 使用和源码 通过前两篇学习引出两个问题 为什么会有锁?锁的作用是什么? 第一个问题如果真正理解了第一篇文章,...

王项雨 的博客 4046

Java多线程安全问题和锁

多线程安全问题和锁 文章目录多线程安全问题和锁线程在jvm中的特点锁的出现synchronized 关键字-监视器锁monitor lock死锁的产生和避免 什么是线程安全问题? 当多个线程同时操作同一个数据是,可能会出现数据不一样的情况,这就是线程安全问题。 线程安全机制用于保证多个线程访问数据时的一致性. 线程安全问题体现在三个方面: 1、原子性 2、可见性 3、有序性 原子操作是不可分割的,...

lzh_99999的博客 4639

Java多线程与高并发专题——保障原子性

Java多线程与高并发专题——保障原子性

从知识输入到知识输出 1174

java关键字synchronized锁详解篇

`synchronized` 是 Java 中用于实现线程同步的关键字,它通过 **内置锁(Monitor Lock)** 确保多线程环境下的原子性、可见性和有序性。

1025

JVM多线程读写和锁

如果在尝试加轻量级锁的过程中,CAS 操作无法成功,这时一种情况就是有其它线程为此对象加上了轻量级锁(有竞争),这时需要进行锁膨胀,将轻量级锁变为重量级锁。情况2:线程2 先执行 num = 2,但没来得及执行 ready = true,线程1 执行,还是进入 else 分支,结。,就是:线程2 执行 ready = true,切换到线程1,进入 if 分支,相加为 0,再切回线程2 执行num = 2。反过来,每个线程都的栈帧都会包含一个锁记录的结构,内部可以存储锁定对象的 Mark Word。

jason_bone_的博客 1394

【高并发】如何使用互斥锁解决多线程的原子性问题?这次终于明白了!

如何解决线程切换带来的原子性问题呢?答案是**保证多线程之间的互斥性。也就是说,在同一时刻只有一个线程在执行!**如果我们能够保证对共享变量的修改是互斥的,那么,无论是单核CPU还是多核CPU,都能保证多线程之间的原子性了。

冰河的专栏 2872

Java中还有哪些方式可以保证多线程环境下的原子性?

Java多线程中保证原子性的主要方式包括:1)原子类(AtomicInteger等)基于CAS实现无锁操作,适合单变量原子操作;2)ReentrantLock提供灵活锁机制,支持复合操作;3)StampedLock优化读多写少场景;4)ThreadLocal通过线程隔离避免竞争;5)Semaphore控制并发访问数;6)ReadWriteLock实现读写分离。选择方案需根据场景:单变量操作用原子类,复合操作用锁,读多写少用StampedLock,无需共享用ThreadLocal。核心原则是平衡性能与原子性需

xh2277659985的博客 1121

Java多线程——如何保证原子性_java怎么保证原子性

线程过多会带来额外的开销,频繁创建和销毁大量线程需要占用系统资源,消耗大量时间。其中包括创建销毁线程的开销、调度线程的开销等等,同时也降低了计算机的整体性能。线程池维护多个线程,等待监督管理者分配可并发执行的任务。这种做法,一方面避免了处理任务时创建销毁线程开销的代价,另一方面避免了线程数量膨胀导致的过分调度问题,保证了对内核的充分利用。

2401_87373733的博客 1651

Java-多线程-增强篇-锁 强化 第一篇

AQS定义了一套多线程访问共享资源的同步器框架,很多同步器的实现都依赖AQS。如ReentrantLock、Semaphore、CountDownLatch …

程序员小刘 792

什么是原子性?volatile能保证原子性吗?

作者简介:大家好,我是码炫码哥,前中兴通讯、美团架构师,现任某互联网公司CTO,兼职码炫课堂主讲源码系列专题代表作:《jdk源码&多线程&高并发》,《深入tomcat源码解析》,《深入netty源码解析》,《深入dubbo源码解析》,《深入springboot源码解析》,《深入spring源码解析》,《深入redis源码解析》等联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬。

smart_an的专栏 810
上一篇: JAVA多线程番外篇 1、单例模式与Volatile
下一篇: JAVA多线程基础篇 6、详解synchronized
悟空学编程
博客等级 码龄12年 32粉丝 123原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悟空学编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值