专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

深入理解volatileSynchronizedReentr

  前沿
  我们都知道,编写正确的并发程序对于程序员来说具备一定的挑战,很多原因是因为我们对Java并发机制的底层实现原理没有足够的理解和认识,因此需要快速而又精准的解决并发类的疑难杂症,就需要理解并发编程的本质,追本溯源,深入分析并发机制的底层原理。
  这些年,为了提高机器的运行性能,我们的CPU、内存、IO设备不断的迭代,但是,在这个快速发展的过程中,有一个核心矛盾一直存在,就是这三者的速度差异。为了合理利用CPU的高性能,平衡这三者的速度差异,计算机体系机构、操作系统、编译程序都做出了贡献,主要体现为:CPU增加了缓存,以均衡与内存的速度差异;操作系统增加了进程、线程,以分时复用CPU,进而均衡CPU与IO设备的速度差异;编译程序优化指令执行次序,使得缓存能够得到更加合理地利用。
  而恰好我们在享受并发编程带来的良好的性能体验,也同时要面对并发编程带来的问题,而这些诡异问题的根据就来自这里!
  一、导致并发问题的主要分为三个源头源头之一:缓存导致的可见性问题源头之二:线程切换带来的原子性问题源头之三:编译优化带来的有序性问题
  只要我们能够深刻理解可见性、原子性、有序性在并发场景下的原理,很多并发问题都会迎刃而出。二、如何解决可见性和有序性问题
  导致可见性的原因是缓存,导致有序性的原因是编译优化(指令的重排序造成的),那解决可见性、有序性最直接的办法就是禁用缓存和编译优化,但是试想,如果真的采用这样的解决方案,我们的程序性能是不是就堪忧了?
  合理的方案应该是按需禁用缓存以及编译优化,为了解决可见性和有序性问题,Java内存模型提供一些规范,本质上可以理解为,Java内存模型规范了JVM如何提供按需禁用缓存和编译优化的方法。具体来说,这些方法包括volatile、synchronized和final三个关键字,以及六项HappensBefore规则。三、volatile3。1volatile关键字作用保证变量写操作的可见性;保证变量前后代码的执行顺序;3。2volatile底层实现原理
  1。内存可见性,保证变量的可见性:当一个被volatile关键字修饰的变量被一个线程修改的时候,其他线程可以立刻得到修改之后的结果。当一个线程向被volatile关键字修饰的变量写入数据的时候,虚拟机会强制它被值刷新到主内存中。当一个线程用到被volatile键字修饰的值的时候,虚拟机会强制要求它从主内存中读取。
  2。禁止JVM指令重排序(防止JVM编译源码生成class时使用重排序):指令重排序是编译器和处理器为了高效对程序进行优化的手段,它只能保证程序执行的结果是正确的,但是无法保证程序的操作顺序与代码顺序一致。这在单线程中不会构成问题,但是在多线程中就会出现问题。非常经典的例子是在双重检查创建单例方法中同时对字段加入volatile,就是为了防止指令重排序。publicclassSingleton{privatevolatilestaticSingletoninstance;privateSingleton(){}publicstaticSingletongetInstance(){if(instancenull){synchronized(Singleton。class){if(instancenull){instancenewSingleton();}}}returninstance;}}复制代码
  由上可以看到,instance变量被volatile关键字所修饰,但是如果去掉该关键字,就不能保证该代码执行的正确性。这是因为instancenewSingleton();这行代码并不是原子操作,其在JVM中被分为如下三个阶段执行:instance分配内存初始化instance将instance变量指向分配的内存空间3。2volatile的写读内存语义
  当写一个volatile变量时,JMM会把线程对应的本地内存中的共享变量值刷新到主内存。当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效,线程之间从主内存读取共享变量的最新值。3。3volatile总结
  volatile用于确保变量的更新操作通知到其他线程
  volatile变量自身具以下特性:
  1volatile保证该变量对所有线程可见,在一个线程修改了变量的值后,新的值对于其他线程是可以立即获取的;
  2volatile禁止指令重排序,即volatile变量不会被存储在寄存器或者其他处理器不可见的地方,因此在读取volatile变量总会返回最新写入的值。
  3对任意单个volatile变量的读写具有原子性,但是类型volatile这种复合操作不具备原子性。
  即:volatile通过禁止指令重排序方式,保证了有序性,但是不能保证原子性。四、JVM锁技术:synchronized
  所谓原子性就是:一个或者多个操作在CPU执行的过程中不被中断的特性,称为原子性。原子性问题的源头是线程切换,如果能够禁用线程切换那不就能解决这个问题了吗?而操作系统做线程切换是依赖CPU中断的,所以禁止CPU发生中断就能够禁止线程切换。
  在单核CPU的场景下,同一时刻只有一个线程执行,禁止CPU中断,意味着操作系统不会重新调度线程,也就是禁止了线程切换,获得CPU使用权的线程就可以不间断地执行,所以两次写操作一定是:要么都被执行,要么都没有被执行,具有原子性。
  但是在多核场景下,同一时刻,有可能有两个线程同时在执行,一个线程执行在CPU1上,一个线程执行在CPU2上,此时禁止CPU中断,只能保证CPU上的线程连续执行,并不能保证同一时刻只有一个线程执行,那就有可能出现并发编程原子性问题。
  同一时刻只有一个线程执行这个条件非常重要,我们称之为互斥。如果我们能够保证对共享变量的修改是互斥的,那么,无论是单核CPU还是多核CPU,就都能保证原子性了。
  当谈到互斥,第一时间一定想到了那个杀手级解决方案:加锁,同时大脑中还会出现以下模型:
  4。1synchronized的作用范围:
  1synchronized作用于成员变量和非静态方法时,锁的是当时对象的实例。
  2synchronized作用于静态方法,锁的是当前Class实例,因为静态方法属于Class而不属于对象。
  3synchronized作用于方法块,锁的是synchronized括号里配置的对象。
  这里简单的举个,当ynchronized用于成员变量和非静态方法时,锁住的是当前对象的实例,具体代码实现如下:
  自定义SynchronizedInstance类DatapublicclassSynchronizedInstance{privateStringid;privateStringsyncInstanceName;publicsynchronizedvoidmethod1(){for(inti0;i3;i){System。out。println(method1execute。。。ii);try{Thread。sleep(3000);}catch(InterruptedExceptione){thrownewRuntimeException(e);}}}publicsynchronizedvoidmethod2(){for(inti0;i3;i){System。out。println(method2execute。。。ii);try{Thread。sleep(3000);}catch(InterruptedExceptione){thrownewRuntimeException(e);}}}}复制代码
  运行MainTestmain()方法,观察控制台打印信息:DatapublicclassMainTest{publicstaticvoidmain(String〔〕args){SynchronizedInstancesynchronizedInstancenewSynchronizedInstance();newThread(newRunnable(){Overridepublicvoidrun(){执行方法1synchronizedInstance。method1();}})。start();newThread(newRunnable(){Overridepublicvoidrun(){执行方法2synchronizedInstance。method2();}})。start();}}复制代码
  上面SynchronizedInstance定义了两个使用synchronized修饰的普通方法,然后再main函数中定义对象的实例并发执行两个方法,从控制台可以明细看到,线程1会等待线程2执行完成后才能执行,这是引用synchronized锁住了当前对象实例synchronizedInstance导致的。
  稍微把程序改一改,现在定义两个实例分别调用两个方法,程序就能并发执行了:DatapublicclassMainTest{publicstaticvoidmain(String〔〕args){实例1SynchronizedInstancesynchronizedInstancenewSynchronizedInstance();实例2SynchronizedInstancesynchronizedInstance2newSynchronizedInstance();newThread(newRunnable(){Overridepublicvoidrun(){实例1执行方法1synchronizedInstance。method1();}})。start();newThread(newRunnable(){Overridepublicvoidrun(){实例2执行方法2synchronizedInstance2。method2();}})。start();}}复制代码
  观察控制台输出:
  结果:method1和method2已经实现并发执行!4。2synchronized锁的几种用法和分析
  1代码块锁,新建一个对象:ObjectlocknewObject(),这里锁的是这个对象的下的Object对象,大部分人喜欢这样用,this是锁整个对象,范围比较大,可能造成该对象中其他加锁方法被干扰,所以可以用这种方式去防止大类对象被使用的时候造成死锁。privateObjectlocknewObject();锁对象lockpublicvoidmethodA(){synchronized(lock){try{Thread。sleep(3000);System。out。println(锁对象lock);}catch(InterruptedExceptione){e。printStackTrace();}}}复制代码
  2代码块锁,锁类对象锁本身,不同的对象相互隔离,互不干扰。锁对象本身publicvoidmethodB(){synchronized(this){try{Thread。sleep(3000);System。out。println(代码块锁,锁类对象锁本身);}catch(InterruptedExceptione){e。printStackTrace();}}}复制代码
  3实例方法锁实例方法锁,同一个实例,多线程阻塞不同的实例,互不干扰,因为锁的不是一个对象不同的实例,不同实例方法锁,多线程也是阻塞等待的,因为是一个对象publicsynchronizedvoidmethodC(){try{Thread。sleep(3000);System。out。println(实例方法锁);}catch(InterruptedExceptione){e。printStackTrace();}}复制代码
  4静态方法锁:static方法,类级别的锁,更对象this无关,同一个类中静态方法锁,多线程阻塞,等待获取类锁才能执行同一个类中不同静态方法锁,多线程阻塞,也需要等待获取类锁才能执行publicsynchronizedstaticvoidmethodD(){try{Thread。sleep(3000);System。out。println(静态方法锁,类级别锁,锁的是当前类Class对象);}catch(InterruptedExceptione){e。printStackTrace();}}复制代码4。3可重入性
  当一个线程试图操作一个由其他线程持有的对象锁的临界资源时,将会处于阻塞状态,但当一个线程再次请求自己持有对象锁的临界资源时,如果当前锁是重入性,请求将会成功,如果当前锁不是可重入性,会等待当前对象锁的释放,实际上该对象锁已被当前线程所持有,不可能再次获得,就会产生死锁,在java中synchronized是基于原子性的内部锁机制,是可重入的,因此在一个线程调用synchronized方法的同时在其方法体内部调用该对象另一个synchronized方法,也就是说一个线程得到一个对象锁后再次请求该对象锁,是允许的,还有就是当子类继承父类时,子类也是可以通过可重入锁调用父类的同步方法,这就是synchronized的可重入性。
  可重入原理:加锁次数计数器JVM负责跟踪对象被加锁的次数线程第一次给对象加锁的时候,计数变为1。每当这个相同的线程再次对象上再次获得锁时,计数会递增每当任务离开时,计数递减,当计数为0的时候,锁会被完全释放4。4synchronized的缺点效率低:锁的释放情况少,试图获得锁时不能设定超时,不能中断一个正在试图获得锁的线程不够灵活(读写锁更灵活:读不加,写才加):加锁和释放锁的时机单一,每个锁仅有单一的添加(某个对象),可能是不够的无法知道是否成功获取到锁(lock可以去尝试成功了做一些逻辑业务,没成功做另一些逻辑)4。5synchronized总结synchronized关键字实现变量的可见性和原子性。synchronized锁机制实现了原子操作,另外Java中实现原子性操作还有通过CAS的方式。synchronized锁的是不是同一个对象,是一个对象,则下一个线程则需要等待上一个线程释放对象锁synchronized虽然能保证线程安全,但是在并发场景下,会影响性能,比如在抢购场景下。还有加锁的方法或者加锁代码块是不是一个很耗时的流程,或者一个公共方法,很多业务逻辑都用到,但是在并发环境下,基本行不通,不同的业务场景下不应该有干扰。五、ReentrantLock
  ReentrantLock是可重入锁,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁,ReentrantLock还支持获取锁的公平性和非公平性选择,公平锁指锁的分配和竞争机制是公平的,即遵循先到先得原则,非公平锁值JVM遵循随机、就近原则分配锁的机制。5。1ReentrantLock核心特性
  ReentrantLock是一种可重入的排它锁,它主要是解决多线程多共享资源竞争的一个问题,它的核心特性有以下几个:ReentrantLock支持重入,也就是说获得锁的线程在释放锁之前再次去竞争同一把锁的时候,不需要加锁可以直接访问。ReentrantLock支持公平和非公平特性。ReentrantLock提供了阻塞竞争锁和非阻塞竞争锁的两种方法,分别是:lock()和tryLock()
  在ReentrantLock中,调用lock()方法获得锁;调用unlock()方法释放锁;ReentrantLock的实现依赖于Java的同步器框架AbstractQueuedSynchronizer(抽象队列同步器,简称AQS),AQS定义了采用volatile修饰的一个共享的整形变量state,主要是用来维护同步状态,AQS底层是采用一个双向链表来实现的,主要是用来存储并发请求线程的一个同步队列。publicabstractclassAbstractQueuedSynchronizerextendsAbstractOwnableSynchronizerimplementsjava。io。Serializable{staticfinalclassNode{共享锁模式staticfinalNodeSHAREDnewNode();排他锁模式staticfinalNodeEXCLUSIVEnull;staticfinalintCANCELLED1;staticfinalintSIGNAL1;staticfinalintCONDITION2;staticfinalintPROPAGATE3;当前节点的前驱节点volatileNodeprev;当前节点的后驱节点volatileNodenext;入队列的线程对象信息volatileThreadthread;链接到等待唤起的下一个节点NodenextWaiter;finalbooleanisShared(){returnnextWaiterSHARED;}等待队列的头部privatetransientvolatileNodehead;等待队列的尾部privatetransientvolatileNodetail;同步状态stateprivatevolatileintstate;}复制代码
  ReentrantLock通过构造函数ReentrantLock(booleanfair)中传递不同的参数来定义不同类型的锁,默认的实现是非公平锁,因为非公平锁算放弃了锁的公平性,但是执行效率明显高于公平锁。ReentrantLocklocknewReentrantLock();参数默认是false,非公平锁ReentrantLocklocknewReentrantLock(true);公平锁复制代码
  如果是非公平锁,竞争锁不需要去判断AQS同步队列里面是否有等待的线程。5。2ReentrantLock支持锁重进入
  重进入是只任意线程在获取到锁之后能够再次获取该锁而不被锁所阻塞,该特性的实现主要需要解决一下两个问题:
  1线程再次获得锁。锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次成功获取。
  2锁的最终释放。线程重复n次获取了锁,随后第n次释放后,其他线程能获取到该锁,锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于0的时候表示锁已经成功释放。六、synchronized和ReentrantLock的比较共同点都是用于控制多线程对共享对象的访问都是可重入锁都保证了可见性和互斥性不同点ReentrantLock显示获取和释放锁;synchronized隐式获取和释放锁,为了避免程序出现异常无法释放锁,需要在实体ReentrantLock时必须在finally语句块中执行释放锁的操作。ReentrantLock可响应中断、可轮回,为处理锁提供了更多的灵活性。ReentrantLock是API级别的,synchronized是JVM级别的。ReentrantLock可以定义公平锁。synchronized底层是同步阻塞机制,采用的是悲观并发策略;ReentrantLock是同步非阻塞,采用的是乐观并发策略。Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置语言实现的。通过Lock可以知道有没有成功获取锁,通过synchronized是无法做到的。

用户有多少人知道魅族这个手机品牌的?第一部魅族手机是MX2,最后一部魅族手机是15Plus,中间穿插着三四部吧,现在家里抽屉里还扔着三个魅族手机,现在不用魅族也不是讨厌,是觉得价格不便宜,还不如买三星捂脸捂脸捂脸别的为什么感觉今年的oppo不如vivo?oppo和vivo都看不上眼,连个中文名都没有,一味地取洋名,崇洋媚外。没有文化自信,何来民族品牌?!老美的苹果手机还有个中文名呢。手机还是首选华为华夏复兴,我辈为之。质量好,科技512内存的小米9Pro手机1800值得入手吗现在?感谢邀请512内存的小米9Pro手机1800值得入手吗现在?实际我觉得这个问题的答案并不是绝对的,因为虽然看上去小米9pro是2019年9月份左右小米发布的一款手机,现在已经过去了35岁以后还有什么事业单位能考的?35岁以后还考事业单位,除了教育与卫生之外,奉劝你没有必要再考了!我们都知道国考省考年龄是硬杠子,不能超过35岁,更重要的是这些考试公平公正信最高可靠。如果超过35岁考事业单位,很高考改革正在进行时,弃选物理的人数会增加吗?对此你怎么看?高考改革之后,弃选物理化学的情况越来越多,如果这个现象持续下去,中国的发展在未来几十年将会越来越慢,甚至陷入停滞,不要说超过美国,就是超过日本都是做梦。浙江近期有一个伟大发明,按照人人都怕癌,癌怕什么?对于人来讲癌症的确可怕,可怕到让人心灵崩溃的地步,不仅仅是对身体折损很大,还对心理也是一种深深的折磨!折磨了身体折磨了心灵不说,还折磨了家人,甚至会消耗一个家庭一生的财富!而癌细胞腰椎盘突出现在腰不痛了腿不痛了,就脚有点酸痛是不是快康复了?你好,很高兴回答你的问题,腰椎间盘突出的主要症状是腰酸困酸疼,下肢疼痛,严重者麻木。虽然腰椎间盘突出患者下肢症状明显,但是根源问题还是在腰椎,所以治疗的话还是要从腰椎入手。根据我十中年女人裸辞后能做什么?感谢邀请,中年女人裸辞后能做什么?为什么女人裸辞捂脸大笑呲牙为什么不说男的裸辞,中年女人自强自力在找份工作,实在没人管检破烂,好多中年女性为生活奔波什么脏话累活都能干,做保姆也行,比特币已经暴跌,显卡不跌钱是什么原因?一btc已经不用显卡挖,它的涨跌与显卡价格涨跌没有必然联系。二卖少的卡就可以赚多的钱,你觉得显卡厂商会加大产能多生产显卡反而少赚钱吗?三目前中国不能生产高端显卡,高端显卡被国外技术有没有踩屎感强且价格在500以内的鞋子推荐?Kenneth的推荐nike的气垫穿的人最好体重大一点,不然用来跑步的话很容易崴脚,而且nike的气垫一口气走多了后脚跟会难受。体重轻的可以考虑飞马系列和阿迪的boost,这两种鞋学完了python能做什么工作?Python作为一门编程语言,近几年借着人工智能发展势头迅猛。学完Python后可以选择以下几个方向。1后台服务端。这个现在一般都跟全栈挂钩,也就是所谓的通吃前后端。从事这个方向学
快递小哥粗心丢失快递,南山公安快速找回获点赞如果找不到,我面临的不只是赔偿,还有可能失去这份工作,真的非常感谢警察同志。近日,市民彭先生连夜给南山公安分局局长信箱,接诉即办平台写了一封感谢信,对提供帮助的民警表示感谢。202梦幻联动!看完许半夏再看梅晓歌,走不出浙江卫视了昨日,浙江卫视官宣12月16日县委大院接档风吹半夏播出。县委大院接档风吹半夏浙江卫视播出登上微博主榜上升榜与文娱榜17位。此前,浙江卫视独家连线赵丽颖登上抖音娱乐榜33位。赵丽颖胡BioactiveMaterials莫尔条纹跨界监测水凝胶体积变化莫尔条纹是18世纪法国研究人员莫尔先生首先发现的一种光学现象。从技术角度上讲,莫尔条纹是两条线或两个物体之间以恒定的角度和频率发生干涉的视觉结果。当人眼无法分辨这两条线或两个物体时整家定制商业模式推动巨头成长丨更优选年终直播录前情摘要11月19日晚,由更新传媒主办,更家居华夏陶瓷网全力支持打造的更优选视频栏目准时开播。作为一档定位知识分享的栏目平台,以轻松有趣有料为特色,同时一诞生就带着华夏陶瓷网一直以外地小哥驰援开启夜派模式发放额外补贴北京快递加速恢复快递小哥不容易,这么冷的天,还有疫情,大家互相理解。辛苦快递小哥们!只要能顺利派送,慢点也能接受。将心比心,有的快递小哥从清晨送货到深夜,令人心疼。近日,北京快递出现延迟的情况受到新品种1斤20元!农民育种家让大白菜告别白菜价人们常说白菜价,是指某样东西的价格十分便宜。在胶州,有一位农民育种家,他深耕新品种研发31年,让胶州大白菜告别白菜价。12月11日,在胶州市里岔镇安家沟村,胶州大白菜研究所所长荆世全国总工会互联网百强企业已全部建立工会中工网北京12月14日电(工人日报中工网记者郑莉朱欣)记者日前从全国总工会获悉,自2021年启动新就业形态劳动者入会集中行动以来,全总和各级工会持续推动互联网百强企业集中建会,截至日均使用量超2100亿次,北斗超GPS已主导国内民用导航定位近日,中国卫星导航系统管理办公室发布消息,截至2022年11月,北斗卫星在民用导航的日均使用量已超2100亿次。北斗系统还在平均单次定位调用卫星数量民用定位精度等多个维度超越GPS尼斯博士的绿色项目,将引领时代趋势!如果我们的学术只知道复述前人的老话,陈陈相因,了无新意,人云亦云,亦步亦趋,不敢越雷池一步,那学术也就丧失了生命力,甚至失去了自己存在的资格和价值。学术如此,科技更是如此。进步才应绝不能让潮州某斯拉刹车成为罗生门J数据既是挡箭牌,又是遮羞布2021年3月29号郑州的荣女士在车库等挪车的时候,拿出手机玩了一会儿王者荣耀,惊心动魄的一幕发生了。车子居然自动加速倒车撞墙,把墙撞出一个大洞,把荣女士也吓个半死。据荣女士讲,当智慧政务云大数据中心技术方案WORD一政务云大数据中心解决案总体架构电子政务数据中心总体架构设计遵循面向业务需求的设计思路,基于业务场景化模块化的设计方法,实现数据中心IT基础架构模块与业务模块松耦合,保证数据中心业
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网