Java线程内存模型

知道JVM内存模型可以在学习多线程的时候更加了解锁的机制和工作方式。下面是我的学习笔记,比较初级。

0x01 内存模型图的思维转换

JVM定义了Java的虚拟内存模型,跟C/C++不一样的是,虚拟内存将物理内存划分了不同的区域,而C/C++是直接映射物理内存的。

笼统的来说,jvm一般将内存分为栈和堆,栈用来存储静态方法和静态变量,而堆用来存储对象和普通变量。

但是如果从线程的角度,内存模型会变成下图的样子

线程内存模型

在这个模型中,变量是在主内存中的,线程各自有各自的工作内存,不会出现相互干扰。

工作内存通过跟主内存之间的操作,实现变量数据的交换共享。而线程工作内存是相互隔离的。这样各线程工作的时候不会对其他线程的工作数据产生影响

0x02 工作内存和主内存之间的操作(单个线程)

两块内存有8种操作。

(lock - unlock)lock将一个主内存变量标记成线程独占,unlock将独占的变量释放

(read - load)read 将主内存的变量读取到CPU中,load操作将read到的变量存入到工作内存中,一定会成对出现

(use - assign)use将工作内存中的变量传递给执行的代码中,当代码需要使用变量值的字节码时,需要这个操作。 assign 赋值操作,将代码中赋值指令出现时,把收到的变量赋值到工作内存中

(store - write)store 将工作内存的变量传送回主内存,但是只是传送,write操作才会将值写入到主内存。而且这两个一定会成对出现

read load ; store write只能成对操作,不能出现只读不用,只返回不存储

不允许线程丢弃assign操作,用完的变量一定会传回主内存,也不允许将未assign的变量从工作内存写回主内存

变量只能从主内存中创建,未初始化的变量线程不能load 或 assign

变量只能被一条线程lock,而且可以lock很多次,必须执行相应条数的unlock才会被释放

线程只能unlock自己lock的变量,未被lock的变量不能执行unlock,不允许unlock其他线程lock的变量

lock变量操作会将工作内存的变量清空,使用这个变量时,相应使用这个变量时,需要重新load 和assign

unlock 前,变量会被重新写入主内存

正如上面4条说明,每两对操作基本都是对应的,成对出现的。(不是绝对)

0x03 特殊的内存操作

下面说一下特例情况

synchronized对内存可见性的影响

首先synchronized关键字在线程同步上,安全性几乎是万能的,导致被滥用的一塌糊涂。

其次synchronized关键字保证了两条线程遵循happens-before的设计原则,两个线程必须一先一后执行。

它会阻止其它线程获取当前对象锁,这样就使得当前对象中被synchronized关键字保护的代码块无法被其它线程访问,也就无法并发执行。

volatile和synchronized的区别

最后synchronized关键字对内存的影响是,当一个线程从一个synchronized块出来时,内存一定会刷新成最新的数据,保证变量的可见性。

接着是volatile关键字

volatile 修饰的变量。面试容易被问,因为大家喜欢用synchronized 来进行同步,忽略了了volatile这个关键字

那么他们的区别是什么?

“可见性”!但是一定要记住,这里的可见性不是绝对的立即可见,虽然volatile变量会将变量的变化及时的反应到其他线程的工作内存中去,但是并不表示被修饰的变量在各线程中会一致,只是使用的时候会被刷新,所以执行引擎不会发现不一致的情况,而实际上,被修饰的变量也会有不同的工作内存中值不一致的情况

volatile 关键字只能保证线程取值的时候,是一致的,等取到工作内存中进行操作时,如果变量被其他线程存回去的话,这时候工作内存的变量就会出现不一致。

下面一段代码会出现比预期值小的情况

publicclassTestVolatail{publicstaticvolatileintadded =0;publicstaticvoidincrease(){        added++;//++ 操作是先取出来,然后再加一,如果想线程安全,试试juc里面的atomic包下的类}publicstaticfinalintADD_ACCOUNTER =10;publicstaticvoidmain(String[] args){        Thread t[] =newThread[ADD_ACCOUNTER];for(inti =0; i < ADD_ACCOUNTER; i++) {            t[i] =newThread(() -> {for(intm =0; m <10000; m++) {                    increase();                }            });            t[i].start();        }while(Thread.activeCount() >1) {            Thread.yield();        }        System.out.println("最终累加值:"+ added);    }}

输出结果:

10个线程,每个对变量做10000次累加,并不是100000,变小了是因为某些线程正在累加的时候,新的较小的值已经覆盖了正在使用的变量,别的线程来取会以这个较小的值为准。

所以volatile只能保证可见性,不能保证一致性

面试的时候最好提一下volatile会禁止jvm做指令重排序,java1.5之后才变成这样的,本篇暂且不表,坑后面再填

long 和 double的特殊性

首先 long 和 double是64位的,这一点是毋庸置疑的。

所以上述8种操作,在面对long类型和double类型的时候,有4种操作read load store write是需要连续执行两次的。虽然JVM中,虽然是允许读取64位数据不是原子操作,但是在商用的JVM中,这些操作都是原子的

而且JVM规范里,强烈“建议”将读取和存放 64位数据的操作做成原子操作的。所以……

另外,多核心处理器中的同一个变量缓存也不是及时同步的,即使有个byte,使用时也会加锁。

附上JVM规范和R大在知乎上的回答:

JVM规范:17.7. Non-atomic Treatment of double and long

R大的回答截取:简单说就是规范说的是:

实现对普通long与double的读写不要求是原子的(但如果实现为原子操作也OK)

实现对volatile long与volatile double的读写必须是原子的(没有选择余地)

(64位JVM的long和double读写也不是原子操作么? - RednaxelaFX的回答 - 知乎

https://www.zhihu.com/question/38816432/answer/78944479

)

如果想亲自试一试,可以看看:证明32位java对long和double的写操作不是原子性的

0x04 总结

以上只是对内存结构和部分读写规则的总结笔记,线程是java必过的硬指标,后面再更新新的学习笔记。

作者:MaxZing

链接:http://www.jianshu.com/p/4e0bfcb1711e

來源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • 知道JVM内存模型可以在学习多线程的时候更加了解锁的机制和工作方式。下面是我的学习笔记,比较初级。 0x01 内存...
    MaxZing阅读 1,699评论 0 6
  • 本文基于周志明的《深入理解java虚拟机 JVM高级特性与最佳实践》所写。特此推荐。 衡量一个服务性能的高低好坏,...
    阳光的技术小栈阅读 1,064评论 0 3
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,183评论 11 349
  • Java8张图 11、字符串不变性 12、equals()方法、hashCode()方法的区别 13、...
    Miley_MOJIE阅读 3,693评论 0 11
  • 上学那会喜欢徐静蕾好像是喜欢她的清纯样貌,直到看了她导演的《一个陌生女人的来信》之后,开始真的喜欢。也许每个文艺女...
    李艳Liz阅读 264评论 0 0