关于jmm:JMM学习笔记二-规则和volatile

学生: 老师,我想请问为什么在月球上物体也会有坠落呢,和在地球上一样诶? 老师: 因为他们都遵循雷同的法则, 咱们依据法则就能够预测行为。但你察看到没有在月球上的坠落速度会慢一点。 到底什么是内存模型?这里咱们来回顾一下《JMM 学习笔记(一) 跨平台的JMM》讲述的货色,在这篇文章外面有两条线, 第一条是硬件性能晋升带来的问题,在单核时代,晋升CPU的方向是优化架构性能和晋升主频速度,然而遗憾的是主频并不能无限度的晋升,主频进步过一个拐点之后,功耗会爆炸晋升。但咱们还须要更强、更快的CPU,多核是一剂良药,引入了多核当前,如何晋升CPU运算性能的问题失去了解决,咱们就能够通过多核来一直的晋升CPU的性能了,某种程度上来说,咱们也能够了解为提供给软件的计算资源在一直的减少,那摆在开发者背后的一个问题是如何更好的应用这些计算资源,如何晋升计算资源的使用率。咱们将联合操作系统的倒退历史来答复这个问题。让咱们从纸带计算机开始讲起,如下图所示 一边读一边执行想来是那时的内存比拟小,然而随着技术的倒退,内存在缓缓的变大,高级语言开始呈现,咱们来察看一下一台计算机同时只能执行一个程序会遇到哪些问题, 咱们先来看下上面一个很简略C语言小程序: #include <stdio.h>#include <stdlib.h>#include <time.h>// argv 用于接管以命令行形式启动传递的参数int main(int argc , char* argv[]){ int to ,sum = 0; // 字符串转int to = atoi(argv[1]); // 打印传入的内部参数 printf("sum: %d\n",to); // 获取output.txt的指针 FILE* fp = fopen("output.txt", "w"); // 获取以后工夫 clock_t start_time = clock(); for(int i = 0 ; i <= to ; i++){ sum = sum + i; // sum = sum + 1; 语句一 // fprintf 将sum写入到fp指向的文件 fprintf(fp,"%d",sum); // 语句二 } fclose(fp); clock_t end_time = clock(); // 获取以后零碎工夫 double total_time = (double)(end_time - start_time) / CLOCKS_PER_SEC; // 计算总运行工夫(秒 printf("Total runtime: %.12f seconds\n", total_time);}而后咱们以命令行形式启动这个程序: ...

June 10, 2023 · 7 min · jiezi

关于jmm:JMM测试利器JCStress学习笔记

前言咱们前文提到,当咱们对实践有一些理解,咱们就渴望验证,如果无奈对实践进行验证,那么咱们就可能对实践将信将疑,那对于Java畛域的并发实践,一贯是难以测试的,更何况调试, 这不仅仅是咱们的认知,OpenJDK的 者也是这么认知的: Circa 2013 (≈ JDK 8) , we suddenly realized there are no regular concurrency tests that ask hard questions about JMM conformance 大概在2013年,也就是JDK8公布的时候,咱们忽然意识到没有惯例的并发测试能够针对JMM的一致性进行深刻探索。 Attempts to contribute JMM tests to JCK were futile: probabilistic tests 尝试将JMM测试奉献给JCK是徒劳的:这是概率性测试。 JVMs are notoriously awkward to test: many platforms, many compilers, many compilation and runtime modes, dependence on runtime profile JVM是出了名的难以测试, 波及多个平台,多个编译器、多种编译和运行时模式,以及依赖的配置文件,所以测试起来比拟麻烦。 这也就是JCStress诞生的起因,咱们心愿有一个测试框架对JMM进行测试,不便咱们验证咱们的猜测是否正确。然而对于JCStress这一方面的材料一贯少之又少,我期待本人是第一手材料的获得者,于是我尝试看JCStress给出的文档, 首先我来到了JCStress在GitHub上的仓库, 看到了上面一段话: In order to understand jcstress tests and maybe write your own, it might be useful to work through the jcstress-samples. The samples come in three groups: ...

May 15, 2023 · 10 min · jiezi

关于jmm:JMM-学习笔记一-跨平台的JMM

前言其实对于并发、多线程这方面的文章,我曾经写过了一些: 《当咱们说起多线程与高并发时》《Java多线程学习笔记(一) 初遇篇》《Java多线程学习笔记(二) 相识篇》《Java多线程学习笔记(三) 甚欢篇》《Java多线程学习笔记(五) 长乐无极篇》《Java多线程学习笔记(六) 长乐未央篇》《Java多线程编程范式(一) 合作范式》《当咱们说起多线程与高并发时》是总领全篇,咱们从操作系统的倒退讲起,为什么要有线程这个概念呈现。《Java多线程学习笔记(一) 初遇篇》讲Java平台下的线程,如何应用和创立,以及引入线程后所面临的问题,为了解决线程平安问题,Java引入的机制,这也是《Java多线程学习笔记(二) 相识篇》探讨的问题,《Java多线程学习笔记(三) 甚欢篇》是讲线程合作,即如何让线程之间合作去解决工作,《Java多线程学习笔记(五) 长乐无极篇》讲了CompletableFuture,这个弱小的异步编排组件,《Java多线程学习笔记(六) 长乐未央篇》 讲ForkJoin模式,《Java多线程编程范式(一) 合作范式》 讲应用Java提供并发外围库来解决一些问题。然而在《Java多线程学习笔记(一) 初遇篇》咱们的探讨绝对还比拟毛糙,过后我的想法是先根本搭建一个模型来疾速的相熟Java的并发编程,在实践中先用起来,咱们没有间接探讨线程平安,什么是线程平安,这个问题在过后的我去看,没有找到一个很完满的定义,还有并发模型,并发是难以验证的,那咱们该如何验证,咱们将对立收拢,对立答复这些问题。 从指令集架构谈起单看指令集架构来说,这是一个有些绝对生疏的名词,让咱们从生存中略微常见的事物讲起,也就是苹果电脑Mac,很多程序员都喜爱Mac,Mac中当初比拟热的一款是Mac m1、m2了,喜爱苹果的人,对m1和m2相当喜爱,这里说的m1和m2也就是CPU的代称,这两款CPU的指令集架构是ARM,那什么是指令集架构? 在答复这个问题的时候,咱们还是要请出《程序是如何运行的(一)》这篇文章的图: 从这幅图咱们能够看到指令集架构是硬件零碎和软件的桥梁,连贯了硬件和软件。那他是什么呢? An Instruction Set Architecture (ISA) is part of the abstract model of a computer that defines how the CPU is controlled by the software. The ISA acts as an interface between the hardware and the software, specifying both what the processor is capable of doing as well as how it gets done. ...

May 3, 2023 · 3 min · jiezi

关于jmm:Java内存模型JMM

Java内存模型(JMM)是 Java 虚拟机的一个重要局部,用于管理程序中的内存拜访。JMM定义了线程间共享内存的拜访规定,确保了内存可见性和原子性,并避免了竞争条件。 JMM的次要内容包含以下几点: 1)可见性:线程间共享内存的可见性,确保了线程间的信息能够相互可见。 2)原子性:确保了内存拜访操作是原子操作,即不可中断。 3)有序性:确保了内存拜访操作的程序。 JMM通过应用同步、锁和 volatile 变量等技术来实现上述规定。应用同步和锁能够保障内存拜访的互斥性,从而确保可见性和原子性;应用 volatile 变量能够保障变量的可见性。 通过遵循 JMM 的规定,开发人员能够保障程序的正确性和可靠性,同时防止常见的内存问题,如竞争条件、死锁等。 1、volatile 可见性的实现原理java中的volatile关键字能够保障变量的可见性。它的实现原理是通过内存屏障和禁止重排序优化来实现的。 1)内存屏障:内存屏障是一种非凡的指令,用于管制处理器缓存中的数据和内存的同步。内存屏障会强制处理器在执行该指令前写回缓存中的数据,并在执行该指令后从内存中读取数据。 2)禁止重排序优化:禁止重排序优化是处理器在执行代码时所做的一种优化,其目标是进步代码的执行效率。在应用volatile关键字润饰的变量被批改时,编译器和处理器都会插入内存屏障指令,从而禁止重排序优化。 当多个线程共享一个volatile变量时,任何一个线程对该变量的批改,都会立即被其余线程看到。这是因为,当一个线程批改了该变量时,会强制将缓存中的数据写回内存,同时禁止重排序优化,从而保障了其余线程在读取该变量时读取的是最新的数据。 总的来说,volatile关键字通过内存屏障和禁止重排序优化,确保了多个线程间共享变量的可见性。应用volatile关键字的变量在读取和批改操作时不会被缓存,而是间接从内存中读取或写入,从而确保了数据的一致性。 然而,请留神,应用volatile关键字仅仅保障了变量的可见性,并不能保障原子性。如果你须要保障变量的原子性,则能够应用Java的原子类或者同步机制。 另外,volatile关键字还有一个毛病,就是性能比拟低。因为它的每次读取和批改操作都要间接从内存中读取或写入,从而造成了大量的内存读写操作,升高了程序的执行效率。因而,应用volatile关键字的中央要适当,不能滥用。

March 2, 2023 · 1 min · jiezi

关于jmm:Java的内存模型

简介Java内存模型的次要目标是定义程序中各种变量的拜访规定,即关注在虚拟机中把变量的值写入内存和从内存中取出的底层细节。这里的变量指的是实例字段、动态字段、形成数组的元素等可被共享的变量。 主内存与工作内存Java内存模型规定所有的变量都存储在主内存(Main Memory)中,每个线程领有本人的工作内存(Working Memory)。 线程的工作内存保留了被该线程应用的变量的主内存正本,线程对变量的读取和赋值操作只能在本人的工作内存中进行,而不能间接读写主内存中的数据。 不同的线程不能间接拜访对方的工作内存中的变量,线程间变量数据的传递必须通过主内存作为中介实现。线程、工作内存和主内存三者的交互关系如图: 内存间的交互对于主内存与工作内存之间的交互协定,即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存的实现细节,Java内存模型定义了八种操作,这八种操作每个都是原子的,不可拆分的,具体如下: lock(锁定):作用于主内存中的变量,它把一个变量标记为线程独占状态unlock(解锁):作用于主内存中的变量,它把一个标记为锁定状态的变量进行锁开释read(读取):作用于主内存中的变量,它把一个变量从主内存中传输到线程的工作内存,以便后续的load操作load(载入):作用于线程工作内存的变量,把read操作从主内存读取的变量加载到工作内存的变量正本中use(应用):作用于线程工作内存的变量,把工作内存中的变量的值传递给执行引擎,当虚拟机遇到一个须要应用变量的字节码指令时将会执行这个操作assign(赋值):作用于线程工作内存的变量,把一个从执行引擎承受的值赋值给工作内存中的变量,当线程遇到一个执行引擎须要赋值的字节码指令时将执行这个操作store(存储):作用于线程工作内存的变量,把一个工作内存中变量的值传递到主内存,以便前面的write操作来写入主内存write(写入):作用于主内存,把store过程传递过去的变量的值写入到主内存中原子性、可见性与有序性Java内存模型的定义和规定都是围绕着在多线程并发执行过程中如何保障原子性、可见性和有序性这三个特色来建设的。 原子性(Atomicity)Java内存模型间接保障的原子性变量操作包含:read、load、assign、use、store、write这六个,基于此,根本数据类型(char,short,int,boolean)拜访、读写都具备原子性(例外就是long和double的非原子性协定)。 如果利用场景须要一个更大范畴的原子性保障,Java内存模型提供了lock和unlock的操作来满足这个需要,虚拟机虽未把lock和unlock间接放开给用户应用,然而提供了更高层次的字节码指令monitorenter和monitorexit来隐式的实现这两个操作,这两个字节码指令反映到Java中的实现就是同步块synchronized关键字。 可见性(Visibility)可见性指的是线程对工作内存中共享变量的值的批改对其余线程立刻可见。Java的内存模型通过在变量批改后把变量的值同步到主内存,在读取变量前从主内存中刷新变量的值到工作内存这种依赖来实现可见性,无论是一般变量还是volatile变量都是如此。 一般变量和volatile的区别在于,volatile的非凡规定保障了新值能立刻同步到主内存,以及每次应用前都强制从主内存刷新,因而,volatile能够保障多线程操作时变量的可见性,而一般变量不能保障这一点。 除了volatile以外,synchronized和final也能够保障共享变量的可见性,其中synchronized的可见性是通过对一个变量执行unlock之前必须强制把变量的值同步到主内存实现的。final关键字的可见性是指,在被final润饰的变量在结构器中一旦被初始化实现,并且结构器没有把“this”的援用传递进来(this援用逃逸会导致其余线程有可能通过这个援用拜访到“初始化一半”的对象),那么其余线程中就能够看到final字段的值。 有序性Java虚拟机的即时编译器会对代码指令进行重排序优化,一般变量仅会保障在线程内代码执行过程中依赖这个变量后果的中央都能获取到正确的后果,然而不能保障变量赋值操作的程序和程序代码的程序是统一的。这种重排序优化在多线程操作下可能会导致意料不到的问题,用上面一段伪代码阐明下: Map configOptions;char[] configText;// 此变量需申明为volatile变量volatile boolean initialized = false;// 上面代码在线程A中运行// 模仿读取配置信息,当读取实现后initialized设置为trueconfigOptions = new HashMap<>();configText = readConfigFile(fileName);processConfigOptions(configText, configOptions);initialized = true;// 上面代码在线程B中执行while(!initialized) { sleep();}// 应用线程A中初始化好的配置信息doSomethingWithConfig();如果指令重排序,线程A中的initialized = true指令可能会在加载配置文件之前就被执行,那么线程B中会呈现应用未加载配置信息的谬误。 volatile关键字能够禁用指令重排序,即不容许扭转initialized = true在代码指令中原有的地位,从而保障了代码依照预期的执行程序执行,确保不会呈现意料之外的问题。 除了volatile关键字之外,synchronized也能够保障多线程环境下的有序性,synchronized的特色保障了同一时刻只能有一个线程执行,多个线程是串行执行的,每一次unlock操作共享变量的批改必须强制刷新到主内存。 后行产生准则Java中只应用volatile和synchronized来保障有序性,那么在操作上就会比拟繁琐,Java语言定义了“后行产生”(Happends-Before)准则,后行产生的操作后果对于前面的操作可见,这些准则无需任何同步器帮助人造存在,能够在代码中间接应用。具体的规定如下: 程序秩序规定:在一个线程内,依照控制流程序,书写在后面的操作后行产生与书序在前面的操作管程锁定规定:一个unlock操作后行产生于后续对同一个锁的的lock操作volatile变量规定:对volatile变量的批改操作后行于对该变量的读取操作线程启动规定:Thread对象的start()办法后行产生于线程的每个操作线程终止规定:线程中的所有操作后行产生于线程的终止操作对象终止规定:一个对象的初始化操作(构造函数执行完结)后行产生于它的finalize()办法的开始传递性:如果A操作后行产生与B操作,B操作后行产生与C操作,那么A操作后行产生于C操作对于可见性的判断,咱们能够应用下面的规定间接进行判断,或者通过多个规定推导进行判断。

April 28, 2022 · 1 min · jiezi

关于jmm:深入理解JMMCPU多核硬件架构剖析及Java内存模型

前言上一节理解synchronized 关键字的底层原理以及锁的降级过程,本节带着大家理解CPU多核硬件架构以及Java内存模型 CPU多核硬件架构分析CPU每次从主内存读取数据比较慢,CPU通常波及多级缓存。CPU读主内存的数据,依照空间局部性准则加载部分快照到缓存中 L1 L2 属于每个CPU中都是独立的缓存,缓存主内存共享变量的数据作为正本,L3属于多个cpu之间共享的缓存。每个cpu之间都有独立二级缓存主内存的数据作为正本,而正本与正本之间是齐全不可见的 总线仲裁机制每次处理器和内存之间的数据传递都是通过一系列步骤来实现的,这一系列步骤称之为总线事务(Bus Transaction)总线会同步试图并发应用总线的事务。在一个处理器执行总线事务期间,总线会禁止其余的处理器和I/O设施执行内存的读/写总线的这种工作机制能够把所有处理器对内存的拜访以串行化的形式来执行在任意工夫点,最多只能有一个处理器能够拜访内存。这个个性确保了单个总线事务之中的内存读/写操作具备原子性处理器提供总线锁定和缓存锁定两个机制来保障简单内存操作的原子性总线锁定总线锁定就是应用处理器提供的一个 LOCK#信号,当其中一个处理器在总线上输入此信号时,其它处理器的申请将被阻塞住,那么该处理器能够独占共享内存总线锁定会将并行的程序,变为串行缓存锁定缓存锁定是某个CPU对缓存数据进行更改时,会告诉缓存了该数据的该数据的CPU摈弃缓存的数据或者从内存从新读取在读写时要依据协定来进行操作,这类协定有MSI、MESI、MOSI、Synapse、Firefly及DragonProtocol等等,然而用的最多的就是MESI。缓存一致性协定会锁缓存行,其性能要比锁总线要高得多MESI协定M 批改 (Modified) 这行数据无效,数据被批改了,和主内存中的数据不统一,数据只存在于本Cache中。E 独享、互斥 (Exclusive) 这行数据无效,数据和主内存中的数据统一,数据只存在于本Cache中。S 共享 (Shared) 这行数据无效,数据和主内存中的数据统一,数据存在于很多Cache中。I 有效 (Invalid) 这行数据有效。JMM内存模型主内存寄存咱们共享变量的数据 工作内存每个CPU对共享变量(主内存)的正本 JMM八大同步标准read(读取):从主内存读取数据load(载入):将主内存读取到的数据写入工作内存中use(应用):从工作内存读取数据来计算assign(赋值):将计算好的值从新赋值到工作内存中store(存储):将工作内存数据写入主内存write(写入):将store过来的变量值赋值给主内存中的变量lock(锁定):将主内存变量加锁,标识位线程独占状态unlock(解锁):将主内存变量解锁,解锁后其余线程能够锁定该变量 并发三大个性可见性、原子性、有序性 可见性可见性指的是当一个线程批改了某个共享变量的值,其余线程是否可能马上得悉这个批改的值 如何保障可见性通过 volatile 关键字保障可见性通过 内存屏障保障可见性通过 synchronized 关键字保障可见性。通过Lock保障可见性通过 final 关键字保障可见性有序性即程序执行的程序依照代码的先后顺序执行。JVM 存在指令重排,所以存在有序性问题。多线程环境下,操作都是无序的,存在指令重排景象和工作内存与主内存同步提早景象 如何保障有序性通过 volatile 关键字保障可见性通过 内存屏障保障可见性通过 synchronized关键字保障有序性通过Lock保障有序性原子性原子性指的是一个操作是不可中断的,即便是在多线程环境下,一个操作一旦开始就不会被其余线程影响 如何保障原子性通过 synchronized 关键字保障原子性通过 Lock保障原子性通过 CAS保障原子性

April 22, 2022 · 1 min · jiezi

关于jmm:JMM内存模型学习

JMM内存模型与CPU缓存模型相似,CPU不是间接去主内存获取数据,而是两头有一个CPU缓存,CPU从缓存中获取数据。在线程内存中有共享变量的正本,线程操作的是这个正本,再同步给主内存,这种机制导致线程1对共享变量进行扭转,其余线程不会实时感知到。 Volatilevolatile关键字保障了共享变量实时可见(可见性)和有序性。(原子性只能通过sync去保障) 缓存一致性协定缓存一致性从硬件层面上保障了被volatile润饰的变量批改后马上会同步给主内存,其余cpu通过总线嗅探机制感知到数据的变动(数据存储到主内存会通过总线),从而使本人的正本生效。 指令重排序CPU在运行过程中,会依据语义本人去优化代码的执行程序。 as-if-serial和happens-before准则大抵就是不管怎么重排序,单线程程序的执行后果不能被扭转。(语句之间没有依赖) 内存屏障内存屏障都是通过硬件层面实现。 双重查看锁单例半初始化问题从字节码水平上来说,对象创立会先赋零值,再初始化。指令重排序可能导致返回还没有进行初始化的对象。

February 24, 2022 · 1 min · jiezi

关于jmm:小白也能看懂的Java内存模型

前言Java并发编程系列开坑了,Java并发编程能够说是中高级研发工程师的必备素养,也是中高级岗位面试必问的问题,本系列就是为了带读者们零碎的一步一步击破Java并发编程各个难点,突破屏障,在面试中所向无敌,拿到心仪的offer,Java并发编程系列文章仍然采纳图文并茂的格调,让小白也能秒懂。 Java内存模型(Java Memory Model)简称J M M,作为Java并发编程系列的开篇,它是Java并发编程的基础知识,了解它能让你更好的明确线程平安到底是怎么一回事。 内容纲要 硬件内存模型程序是指令与数据的汇合,计算机执行程序时,是C P U在执行每条指令,因为C P U要从内存读指令,又要依据指令批示去内存读写数据做运算,所以执行指令就免不了与内存打交道,晚期内存读写速度与C P U处理速度差距不大,倒没什么问题。 C P U缓存随着C P U技术疾速倒退,C P U的速度越来越快,内存却没有太大的变动,导致内存的读写(IO)速度与C P U的处理速度差距越来越大,为了解决这个问题,引入了缓存(Cache)的设计,在C P U与内存之间加上缓存层,这里的缓存层就是指C P U内的寄存器与高速缓存(L1,L2,L3) 从上图中能够看出,寄存器最快,主内最慢,越快的存储空间越小,离C P U越近,相同存储空间越大速度越慢,离C P U越远。 C P U如何与内存交互C P U运行时,会将指令与数据从主存复制到缓存层,后续的读写与运算都是基于缓存层的指令与数据,运算完结后,再将后果从缓存层写回主存。 上图能够看出,C P U根本都是在和缓存层打交道,采纳缓存设计补救主存与C P U处理速度的差距,这种设计不仅仅体现在硬件层面,在日常开发中,那些并发量高的业务场景都能看到,然而凡事都有利弊,缓存尽管放慢了速度,同样也带来了在多线程场景存在的缓存一致性问题,对于缓存一致性问题前面会说,这里大家留个印象。 Java内存模型Java内存模型(Java Memory Model,J M M),后续都以J M M简称,J M M 是建设在硬件内存模型根底上的形象模型,并不是物理上的内存划分,简略说,为了使Java虚拟机(Java Virtual Machine,J V M)在各平台下达到统一的内存交互成果,须要屏蔽上游不同硬件模型的交互差别,对立标准,为上游提供对立的应用接口。 J M M是保障J V M在各平台下对计算机内存的交互都能保障成果统一的机制及标准。 形象构造J M M形象构造划分为线程本地缓存与主存,每个线程均有本人的本地缓存,本地缓存是线程公有的,主存则是计算机内存,它是共享的。 不难发现J M M与硬件内存模型差异不大,能够简略的把线程类比成Core外围,线程本地缓存类比成缓存层,如下图所示 ...

April 30, 2021 · 2 min · jiezi

关于jmm:最新详细的JMM内存模型三天熬夜血肝

常识图谱 前言网上并发以及JMM局部的内容大部分都特地的乱,也不好整顿。花了三四天工夫才整顿了一篇,有些概念的货色,是须要理解的,也标注进去了。 标注:在学习中须要批改的内容以及笔记全在这里 www.javanode.cn,谢谢!有任何不妥的中央望纠正 并发编程的优缺点1. 为什么要用到并发多核的CPU的背景下,催生了并发编程的趋势,通过并发编程的模式能够将多核CPU的计算能力施展到极致,性能失去晋升 面对简单业务模型,并行程序会比串行程序更适应业务需要,而并发编程更能吻合这种业务拆分 2. 并发编程有哪些毛病2.1 频繁的上下文切换工夫片是CPU调配给各个线程的工夫,因为工夫十分短,所以CPU一直通过切换线程,让咱们感觉多个线程是同时执行的,工夫片个别是几十毫秒。而每次切换时,须要保留以后的状态起来,以便可能进行复原先前状态,而这个切换时十分损耗性能,过于频繁反而无奈施展出多线程编程的劣势。通常缩小上下文切换能够采纳无锁并发编程,CAS算法,应用起码的线程和应用协程。 2.2 线程平安多线程编程中最难以把握的就是临界区线程平安问题,略微不留神就会呈现死锁的状况,一旦产生死锁就会造成零碎性能不可用。 public class DeadLockDemo { private static String resource_a = "A"; private static String resource_b = "B"; public static void main(String[] args) { deadLock(); } public static void deadLock() { Thread threadA = new Thread(new Runnable() { @Override public void run() { synchronized (resource_a) { System.out.println("get resource a"); try { Thread.sleep(3000); synchronized (resource_b) { System.out.println("get resource b"); } } catch (InterruptedException e) { e.printStackTrace(); } } } }); Thread threadB = new Thread(new Runnable() { @Override public void run() { synchronized (resource_b) { System.out.println("get resource b"); synchronized (resource_a) { System.out.println("get resource a"); } } } }); threadA.start(); threadB.start(); }}通常能够用如下形式防止死锁的状况 ...

January 19, 2021 · 3 min · jiezi

关于jmm:JMM

JMM概念JMM即为JAVA 内存模型(java memory model)。自身是一种形象的概念,并不实在存在,它形容的是一组规定或标准,通过这组标准定义了程序中各个变量(包含实例字段,动态字段和形成数组对象的元素)的拜访形式。是为了屏蔽零碎和硬件的差别,让一套代码在不同平台下能达到雷同的拜访后果。 内存划分工作内存对应寄存器和高速缓存主内存对应硬件的物理内存线程对变量的读取和写入,间接在工作内存中操作,而不能间接去操作主内存中的变量。然而这样就会呈现一个问题,当一个线程批改了本人工作内存中变量,对其余线程是不可见的,会导致线程不平安的问题。 模型特色原子性 - 保障指令不会受到线程上下文切换的影响被synchronized关键字或其余锁包裹起来的操作也能够认为是原子的。从一个线程察看另外一个线程的时候,看到的都是一个个原子性的操作。 2.可见性 - 保障指令不会受 cpu 缓存的影响 每个工作线程都有本人的工作内存,所以当某个线程批改完某个变量之后,在其余的线程中,未必能察看到该变量曾经被批改。volatile关键字要求被批改之后的变量要求立刻更新到主内存,每次应用前从主内存处进行读取。因而volatile能够保障可见性。除了volatile以外,synchronized和final也能实现可见性。synchronized保障unlock之前必须先把变量刷新回主内存。final润饰的字段在结构器中一旦实现初始化,并且结构器没有this逸出,那么其余线程就能看到final字段的值。 3.有序性 - 保障指令不会受 cpu 指令并行优化的影响java的有序性跟线程相干。如果在线程外部察看,会发现以后线程的所有操作都是有序的。如果在线程的内部来察看的话,会发现线程的所有操作都是无序的。因为JMM的工作内存和主内存之间存在提早,而且java会对一些指令进行从新排序。

January 5, 2021 · 1 min · jiezi