多线程同步

synchronized同步的实现——多线程购票 同步的由来 当两个或两个以上的线程需要共享资源,必须使用某种方法来确定资源在某一时刻仅被一个线程占用,达到此目的的过程叫做同步。(synchronized) 同步的实现 方法级同步(method-level synchronized) synchronized void method( ) { //同步的方法 } 对象级同步( block-level syn... 阅读详情

目录

1. 为什么引入同步机制

2. 竞态条件和内存可见性

2.1 竞态条件

2.2 内存可见性

3. 线程同步方法

3.1 synchronzied

3.2 JDK1.5的锁 Lock

3.3 volatile关键字


1. 为什么引入同步机制

多线程为什么要采用同步机制,因为不同的线程有自己的栈,栈中可能引用了多个对象,而多个线程可能引用到了堆中的同一个或多个对象,而线程的栈内存当中的数据只是临时数据,最终都是要刷新到堆中的对象内存,这里的刷新并不是最终的状态一次性刷新,而是在程序执行的过程中随时刷新(肯定有固定的机制,暂不考虑),也许在一个线程中被应用对象中的某一个方法执行到一半的时候就将该对象的变量状态刷新到了堆的对象内存中,那么再从多线程角度来看,当多个线程对同一个对象中的同一个变量进行读写的时候,就会出现类似数据库中的并发问题。

假设银行里某一用户账户有1000元,线程A读取到1000,并想取出这1000元,并且在栈中修改成了0但还没有刷新到堆中,线程B也读取到1000,此时账户刷新到银行系统中,则账户的钱变成了0,这个时候也想去除1000,再次刷新到行系统中,账号的钱变成0,这个时候A,B都取出1000元,但是账户只有1000,显然出现了问题。针对上述问题,假设我们添加了同步机制,那么就可以很容易的解决。

怎样解决这种问题呢,在线程使用一个资源时为其加锁即可。访问资源的第一个线程为其加上锁以后,其他线程便不能再使用那个资源,除非被解锁。

2. 竞态条件和内存可见性

线程和线程之间是共享内存的,当多线程对共享内存进行操作的时候有几个问题是难以避免的,竞态条件和内存可见性。

2.1 竞态条件

当多线程访问和操作同一对象的时候计算的正确性取决于多个线程的交替执行时序时,就会发生竞态条件

最常见的竞态条件为:

  1. 先检测后执行。执行依赖于检测的结果,而检测结果依赖于多个线程的执行时序,而多个线程的执行时序通常情况下是不固定不可判断的,从而导致执行结果出现各种问题。
  2. 延迟初始化(最典型即为单例)

上文中说到的加锁就是为了解决这个问题,常见的解决方案有:

  • 使用synchronized关键字
  • 使用显式锁(Lock)
  • 使用原子变量

2.2 内存可见性

关于内存可见性问题要先从内存和cpu的配合谈起,内存是一个硬件,执行速度比CPU慢几百倍,所以在计算机中,CPU在执行运算的时候,不会每次运算都和内存进行数据交互,而是先把一些数据写入CPU中的缓存区(寄存器和各级缓存),在结束之后写入内存。这个过程是及其快的,单线程下并没有任何问题。

但是在多线程下就出现了问题,一个线程对内存中的一个数据做出了修改,但是并没有及时写入内存(暂时存放在缓存中);这时候另一个线程对同样的数据进行修改的时候拿到的就是内存中还没有被修改的数据,也就是说一个线程对一个共享变量的修改,另一个线程不能马上看到,甚至永远看不到。

这就是内存的可见性问题。

解决这个问题的常见方法是:

  • 使用volatile关键字
  • 使用synchronized关键字或显式锁同步

3. 线程同步方法

3.1 synchronzied

同步代码块

每个java对象都有一个互斥锁标记,用来分配给线程,synchronized(o){ } 对o加锁的同步代码块,只有拿到锁标记的线程才能够进入对o加锁的同步代码块。

同步方法

synchronized作为方法修饰符修饰的方法被称为同步方法,表示对this加锁的同步代码块(整个方法都是一个代码块)。

 

3.2 JDK1.5的锁 Lock

在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
ReenreantLock类的常用方法有:

//创建一个锁对象
Lock lock = new ReentrantLock();

//上锁(进入同步代码块)
lock.lock();

//解锁(出同步代码块)
lock.unlock();

//尝试拿到锁,如果有锁就拿到,没有拿到不会阻塞,返回false
tryLock();

注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用 

ReentrantLock具有和synchronized相似的作用,但是更加的灵活和强大。

synchronized和ReentrantLock的区别

  1. 两者都是互斥锁,所谓互斥锁:同一时间只有一个拿到锁的线程才能够去访问加锁的共享资源,其他的线程只能阻塞
  2. 都是重入锁,用计数器实现;

    所谓重入就是可以重复进入同一个函数

    假设一种场景,一个递归函数,如果一个函数的锁只允许进入一次,那么线程在需要递归调用函数的时候,应该怎么办?退无可退,有不能重复进入加锁的函数,也就形成了一种新的死锁。

    重入锁的出现就解决了这个问题,实现重入的方法也很简单,就是给锁添加一个计数器,一个线程拿到锁之后,每次拿锁都会计数器加1,每次释放减1,如果等于0那么就是真正的释放了锁。

  3. ReentrantLock独有特点
    1. ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁
    2. ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程
    3. ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制

3.3 volatile关键字

volatile 修饰符 用来保证可见性

当一个共享变量被volatile修饰的时候,他会保证变量被修改之后立马在内存中更新,另一线程在取值的时候需要去内存中读取新的值。

注意:尽管volatile 可以保证变量的内存可见性,但是不能够保存原子性,对于b++这个操作来说,并不是一步到位的,而是分为好几步的,读取变量,定义常量1,变量b加1,结果同步到内存。虽然在每一步中获取的都是变量的最新值,但是没有保证b++的原子性,自然无法做到线程安全

 

参考:java 多线程 --同步

VC++ MFC 多线程及线程同步  VC++ MFC 多线程及线程同步关键词: MFC    多线程及线程同步                                           VC++6.0; 线程同步;临界区;事件;互斥;信号量;   使线程同步  在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作。更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解。 阅读详情

相关推荐

ADF4002分频器避坑指南:常见配置错误及解决方案

本文深入解析了ADF4002分频器在实战应用中的常见陷阱与解决方案。内容涵盖寄存器配置逻辑、硬件PCB布局要点、软件驱动时序细节及系统化调试方法,重点阐述了如何避免因配置错误导致芯片无法正常工作的问题,帮助工程师高效完成高精度频率合成系统设计。

weixin_29192141的博客 96

java 多线程 --同步

java 多线程 --同步

Spontaneous_0的博客 346

在Ubuntu 20.04上,用EtherCAT Igh 1.6.2驱动高创BD3E伺服电机(附完整C代码)

本文详细介绍了在Ubuntu 20.04实时内核环境下,使用EtherCAT Igh 1.6.2主站驱动高创BD3E伺服电机的完整实现方案。从实时系统配置、伺服电机PDO映射到精确控制线程设计,提供了完整的C代码样例和实际项目中的调试技巧,帮助开发者实现工业自动化中的高精度运动控制。

weixin_30772105的博客 111

多线程同步机制

为什么要引入同步机制在多线程环境中,可能会出现两个甚至更多的线程试图同时访问同一个资源。必须对这种潜在的资源冲突进行预防。解决方法在线程使用一个资源时为其加入锁机制。访问资源的第一个线程对其加上锁之后,其他线程便不能再使用那个资源,除非被解锁。例子比如银行取钱的例子: 首先有一个银行账户:/** * 银行账户类,里面的余额为1000 */ class Bank { private in

qianyiyiding的专栏 1998

企业级Windows 10镜像封装实战:从规划到部署的完整指南

系统部署与镜像封装是企业IT运维中的核心基础技术,其原理在于通过创建预配置的系统模板,实现大规模计算机环境的快速、标准化部署。这项技术的核心价值在于将重复性手动操作转化为自动化流程,显著提升运维效率,保障环境一致性,并强化安全基线管理。在实际应用场景中,它尤其适用于新设备批量初始化、系统恢复和标准化环境构建。本文聚焦于Windows 10镜像的封装实践,深入探讨了使用Sysprep进行系统通用化处理以及通过DISM工具捕获WIM格式镜像的具体方法,为企业IT人员提供从零构建标准化系统镜像的完整路径。

weixin_33843947的博客 356

Python+Selenium实现抖音博主批量监控:300+账号实时更新通知(附完整代码)

本文详细介绍了如何使用Python和Selenium构建一个高可用的抖音博主批量监控系统。通过架构设计、Cookie管理、高效轮询与差异检测等核心模块,实现300+账号的实时更新追踪与通知。文章提供了完整的代码实现,并重点探讨了性能优化、异常处理及服务器部署等实战经验,帮助开发者打造稳定、可控的自动化监控解决方案。

weixin_29274969的博客 195

多线程状态下使用同步机制的本质原因

简述 在Java的学习中必然会遇到多线程和同步问题,对于初学者一般只会理解到相关api的使用,但是很少能够真正知道为什么要对多线程环境下的对象进行同步,接下来我就谈谈自己的一些理解。 JVM堆与JVM栈宏观室是分离的,而微观上则又相互联系,这种分配方式使得JVM堆中的内容可以被多个JVM栈共享(也可以理解为多个线程访问同一个或者多个对象)。这种共享的收益是很多的。一方面这种共享提供了一种有效的

笃行淡言 4524

shopro 商城,2025年新申请的微信支付提示失败,支付提示 Get Wechat Public Cert Error 问题的修复办法

shopro 商城,最近新申请的微信支付商户 支付提示 Get Wechat Public Cert Error 问题的修复办法

行走的卡路里 1245

多线程:解释线程同步的必要性

为什么需要线程同步? 当多个线程同时运行时,线程的调度由操作系统决定,程序本身无法决定。因此,任何一个线程都有可能在任何指令处被操作系统暂停,然后在某个时间段后继续执行。 这个时候,有个单线程模型下不存在的问题就来了:如果多个线程同时读写共享变量,会出现数据不一致的问题。 比如: public class Main { public static void main(String[] args) throws Exception { var add = new AddThread()

追求大牛之人的博客 6496

芯片设计新手必看:5分钟搞懂工艺角(Process Corner)到底是什么,为啥仿真总要用它?

本文详细解析了芯片设计中的工艺角(Process Corner)概念及其在仿真中的重要性。通过类比马拉松运动员的性能差异,解释了晶体管制造过程中的天然波动,并介绍了TT/FF/SS等工艺角代码的含义。文章还探讨了为何需要跑全工艺角仿真,以及现代芯片验证的完整流程,包括PVT矩阵和多模式分析(MMMC),帮助芯片设计新手快速掌握这一关键概念。

weixin_28713947的博客 246

肖特基二极管选型参数,结构原理,工艺与注意问题总结

肖特基二极管(Schottky Diode)是一种特殊的二极管,也被称为肖特基势垒二极管。它是利用金属与半导体接触形成的金属-半导体结原理制成的。与传统的PN结二极管相比,肖特基二极管具有更低的正向压降、更高的开关速度、更高的反向恢复时间以及更好的温度稳定性等特点。本文对肖特基二极管的工作原理,结构特点,工艺流程,选型参数及设计注意事项进行总结。

fydar的博客 813

谈谈你对多线程同步机制的理解?

线程同步是为了确保线程安全,所谓线程安全指的是多个线程对同一资源进行访问时,有可能产生数据不一致问题,导致线程访问的资源并不是安全的。(如果多线程程序运行结果和单线程运行的结果是一样的,且相关变量的值与预期值一样,则是线程安全的。) java中与线程同步有关的关键字/类包括: volatile、synchronized、Lock、AtomicInteger等concurrent包下的原子类。。...

suncat的博客 1499

74、光谱成像在电子内窥镜及色彩理论中的应用

本文探讨了光谱成像在电子内窥镜中的应用及其与色彩理论的深度融合。通过分析FICE技术、色彩再现模型及胃黏膜光谱测量,展示了光谱信息在提升医学诊断准确性方面的潜力。同时,系统阐述了颜色的物理属性、标准表示方法、同色异谱现象、颜色测量技术(密度法与比色法)以及CIELAB等均匀颜色空间的构建原理。结合流程图与对比表格,梳理了从光信号获取到颜色处理的完整路径,并展望了人工智能与新型视觉模型在未来医疗成像与色彩科学中的发展方向。

g2h3i4j5的博客 153

Java中关于同步,异步,多线程,多线程同步,并发,并行的一些总结

1.同步与异步1.1同步在多线程的环境中,经常会碰到数据共享的情况,即当多个线程共同需要访问一个资源时,他们需要以某种顺序来确保该资源在某一时刻只能被一个线程使用,否则,程序的运行结果将是不可预料的,在这种情况下就必须对数据进行同步,例如多个线程同时对同一数据进行写操作,即当线程A需要使用某个资源时,如果这个资源正在被线程B使用,同步机制就会让线程A一直等待下去,直到线程B结束对该资源的使用后,线程

优快云_FTD的博客 3172

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

java多线程 —— 多线程同步器

1、什么是多线程同步器? 可以理解为,用于控制多线程之前同步动作的工具。 2、为什么使用多线程同步器? 在实际应用中,我们希望多线程根据某些一些特定的规则执行。因此有了多线程同步器,通过不同的多线程同步器,可以让多线程实现多样的行为。 3、多线程同步器介绍 3.1、Samaphore 应用场景:对于一组有限制都资源访问。比如餐厅有2个位置但同时有10个人要吃饭,则要控制10个人对餐位的并发实用。即当餐位有空余时,就会有人用餐,没有空余时,则进入阻塞等待。 用法:定义Semaphore变量sem

向来缘浅,奈何情深 2741

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

一文讲清多线程和多线程同步

一个进程内多个线程并发执行的情况就叫多线程,每个线程是一个独立的执行流,多线程是一种编程模型,它与处理器无关、跟设计有关。并行计算:充分利用多核,提升整体吞吐,加快执行速度。后台任务处理:将后台线程和主线程分离,在特定场景它是不可或缺的,如:响应式用户界面、实时系统等。我们用2个例子作说明。同一进程内的多个线程会共享数据,对共享数据的并发访问会出现(竞争状况)。协调多个线程对共享数据的访问,避免出现数据不一致的情况。

excellent_fish_c的博客 1879

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

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

什么是同步,如何在多线程间保持同步

内容: 在前面的文章中,所涉及的线程大多都是独立的,而且异步执行。也就是说每个线程都包含了运行时自身所需要的数据或方法,而不需要外部的资源或方法,也不必关心其他线程的状态或行为。但是,有时候在进行多线程的程序设计中需要实现多个线程共享同一段代码,从而实现共享同一个私有成员或类的静态成员的目的。这时,由于线程和线程之间互相竞争CPU资源,使得线程无序地访问这些共享资源,最终可能导致无法得到正确的结

そうふくのスタジオ 782

多线程的同步问题

多线程的同步问题 1.背景 例子:创建个窗口卖票,总票数为100张.使用实现Runnable接口的方式 * 1.问题:卖票过程中,出现了多人同时买一张票,票买完了还在买 -->出现了线程的安全问题 2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票。 3.如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来。直到线程a操作完ticket时,其他线程才可以开始操作ticket。这种情况即使线程a出现了阻塞,也不能被改变。 2.Java解决方案

chengzi_cocc的博客 315

多线程—7种同步方法

多线程—7种同步方法 原文https://www.cnblogs.com/cxxjohnson/p/8536257.html#h3 关于线程同步(7种方式) 同步方法 同步代码块 使用重入锁实现线程同步(ReentrantLock) 使用特殊域变量(volatile)实现同步(每次重新计算,安全但并非一致) 使用局部变量实现线程同步(ThreadLocal)以空间换时间 使用原子变量实现线程同步(AtomicInteger(乐观锁)) 使用阻塞队列实现线程同步(BlockingQueue.

yuyeqianhen的博客 3074

Python 多线程同步

Python 提供了丰富的线程同步机制,从基础的LockSemaphore到更高级的ConditionEvent和Barrier,以及线程安全的Queue。选择何种机制取决于具体场景:保护简单共享变量可用Lock;控制资源并发数用Semaphore;实现线程间依赖和通知用Condition或Event;在线程间传递数据则优先使用Queue。同时,必须注意 GIL 对多线程并行的限制,并遵循避免死锁、最小化锁范围等最佳实践,才能编写出高效、健壮的多线程程序。

xingzhemengyou1的博客 1293

java 常用多线程同步_Java多线程之线程同步

多线程共享数据(多个线程共同访问相同的数据),需要进行数据同步,保证同一数据、同一时刻只能被一个线程访问。使用同步是为了防止多个线程同一时刻对同一数据进行读写,如果对同一数据数据都只进行读操作、不进行修改,则不必使用同步。以售票为例 不使用同步public class SaleTicketThread extendsThread {private static int ticket = 100...

weixin_36058685的博客 215

java多线程同步编程

学习java有一段时间了,一直对java的多线程同步理解的不够深刻,今天将我学习的过程记录下来帮助大家一起来学习深刻理解java的多线程同步策略 现实生活中多线程同步场景很多,比如说我的银行卡里面的money数是100,我自己正在银行存10元,而这时候我老婆正在超市用支付宝消费10,那么我的余额应该是不变对吧,但是如果没有做线程同步那么数字会发生变化,这是很危险的。 我们先来见识一下多线程运行

zfszhangyuan的博客 3449

Java多线程——线程同步

简单讲解了java多线程中可能会出现的线程同步问题,并讲解怎么使用synchronized和ReentrantLock锁来解决问题

2501_90745824的博客 1095

c#多线程同步执行

在C()方法中,其实是遇到await后,代码则是返回task.run上面去了,然后从上到下再执行,执行到第二方法,又返回task.run上面去了,然后再从上到下执行,以此类推,所以和同步执行的时间基本上一样的。多线程对于单线程来说的,单线程,就是开启一个线程进行工作,多线程则是,开启多个线程进行多个工作,并且没有顺序,没有规律性。多线程同步,则是,既有同步和多线程的特点,即开启多个线程进行工作的同时,还要按照顺序和规律执行。耗时5052,并且是按照顺序执行的,而且界面还可以拖动,正是我们需要的。...

故里2130 6448

C++ 多线程同步

在C++中,多线程同步是非常重要的,因为多个线程同时访问共享资源可能会导致数据竞争和不一致性

weixin_39926429的博客 1966
上一篇: 线程间通信
下一篇: LeetCode | Add Two Numbers
zhangpower1993
博客等级 码龄11年 100粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值