多线程学习之JAVA语言内存模型和线程安全实例讲解
小标 2018-11-05 来源 : 阅读 1115 评论 0

摘要:本文主要向大家介绍了多线程学习之JAVA语言内存模型和线程安全实例讲解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了多线程学习之JAVA语言内存模型和线程安全实例讲解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

1.线程安全是什么:


指某个函数、函数库在多线程环境中被调用时,能够正确地处理各个线程的局部变量,使程序功能正确完成。


2.内存模型


–每一个线程有一个工作内存和主存独立


–工作内存存放主存中变量的值的拷贝


当数据从主内存复制到工作存储时,必须出现两个动作:第一,由主内存执行的读(read)操作;第二,由工作内存执行的相应的load操作;当数据从工作内存拷贝到主内存时,也出现两个操作:第一个,由工作内存执行的存储(store)操作;第二,由主内存执行的相应的写(write)操作。


对于普通变量,一个线程中更新的值,不能马上反应在其他变量中


如果需要在其他线程中立即可见,需要使用volatile关键字


3.由于内存模型而引出线程安全的一些特性:


–原子性


原子性是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其它线程干扰。而且CPU执行指令是一条一条的,所以在应用里同时对一个对象进行读写,都不会影响一致性。


–可见性


一个线程修改了变量,其他线程可以立即知道。


–保证可见性的方法


–volatile


–synchronized(unlock之前,写变量值回主存)


–final(一旦初始化完成,其他线程就可见)


–有序性


在本线程内,操作都是有序的


在线程外观察,操作都是无序的。(指令重排或主内存同步延时)


指令重排


-指令重排是JVM对字节码执行的一个优化


-一条指令的执行是可以分为很多步骤的


–取指IF


–译码和取寄存器操作数ID


–执行或者有效地址计算EX


–存储器访问MEM


–写回WB


该语句需要9步才可以执行完,


我们看下以下语句的指令正常的执行步骤


a=b+c


d=e-f


从该图可以看出,这2条语句需要执行14步


我们再看下通过指令重排的执行步骤


从该图可以看出,重排后只需要12步就可以执行完


-指令重排的好处


可以使流水线更加顺畅


减轻处理压力,加快处理时间


-线程内串行语义


写后读 a = 1;b = a; 写一个变量之后,再读这个位置。


写后写 a = 1;a = 2; 写一个变量之后,再写这个变量。


读后写 a = b;b = 1; 读一个变量之后,再写这个变量。


以上语句不可重排


编译器不考虑多线程间的语义


可重排:a=1;b=2;


-破坏线程间的有序性


class OrderExample {  


int a = 0;  


boolean flag = false;  


public void writer() {  


a = 1;                     


flag = true;             


}  


public void reader() {  


if (flag) {                  


int i =  a +1;        


……  


}  


}  


}  


        线程A首先执行writer()方法


        线程B线程接着执行reader()方法


        线程B在int i=a+1 是不一定能看到a已经被赋值为1


        因为在writer中,两句话顺序可能打乱


    -保证有序性的方法


[java] view plain copy


class OrderExample {  


int a = 0;  


boolean flag = false;  


public synchronized void writer() {  


a = 1;                     


flag = true;             


}  


public synchronized void reader() {  


if (flag) {                  


int i =  a +1;        


……  


}  


}  


}  


        同步后,即使做了writer重排,因为互斥的缘故,reader 线程看writer线程也是顺序执行的。


    -指令重排的基本原则


        – 程序顺序原则:一个线程内保证语义的串行性


        – volatile规则:volatile变量的写,先发生于读


        – 锁规则:解锁(unlock)必然发生在随后的加锁(lock)前


        – 传递性:A先于B,B先于C 那么A必然先于C


        – 线程的start方法先于它的每一个动作


        – 线程的所有操作先于线程的终结(Thread.join())


        – 线程的中断(interrupt())先于被中断线程的代码


    对象的构造函数执行结束先于finalize()方法


          

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!


本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved