没有合适的资源?快使用搜索试试~ 我知道了~
首页JAVA线程安全及性能的优化
不同的平台,内存模型是不一样的,但是jvm的内存模型规范是统一的。其实JAVA的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题:可见性和有序性。我们都知道计算机有高速缓存的存在,处理器并不是每次处理数据都是取内存的。JVM定义了自己的内存模型,屏蔽了底层平台内存管理细节,对于java开发人员,要清楚在jvm模型的基础上,如果解决多线程的可见性和有序性。
资源详情
资源推荐
JAVA 线程安全
JAVA 内存模型
不同的平台,内存模型是不一样的,但是 的内存模型规范是统一的。其实 的多线程并发问
题最终都会反映在 的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。
总结 的内存模型,要解决两个主要的问题:可见性和有序性。我们都知道计算机有高速缓存的存在,
处理器并不是每次处理数据都是取内存的。 定义了自己的内存模型,屏蔽了底层平台内存管理细节,
对于 开发人员,要清楚在 模型的基础上,如果解决多线程的可见性和有序性。
那么,何谓可见性呢?多个线程之间是不能互相传递数据通信的,他们之间的沟通只能通过共享变
量来进行。 内存模型规定了 有主内存,主内存是多个线程共享的。当 一个对象的时候,
也是被分配在主内存中,每个线程都有自己的工作内存,工作内存存储了主存的某些对象的副本,当然线
程的工作大小是有限制的。当线程操作某个对象时,执行顺序如下:
从主存复制变量到当前工作内存
执行代码,改变共享变量值
用工作内存数据刷新主存相关内容
规范定义了线程对主存的操作指令:、、、、、。当一个共享变量在
多个线程的工作内存中都有副本时,如果一个线程修改了这个共享变量,那么其他线程应该能够看到这个
被修改之后的值,这就是多线程的可见性问题。
那么什么是有序性呢?线程在引用变量时不能直接从主内存中引用,如果线程工作内存中没有该变
量,则会从主内存中拷贝一个副本到工作内存中,这个过程为 ,完成后线程会引用该副本。当同
一线程再度引用该字段时,有可能从主内存中获取变量副本,也有可能直接引用原来的副本
,也就是说 、、 顺序可以由 实现系统决定。
线程不能直接为主内存中字段赋值,它会将值指定给工作内存中的变量副本,完成后这个变
量副本会同步到主存储区,至于何时同步过去,根据 实现系统决定。有该字段,则会从
主内存中将该字段赋值到工作内存中,这个过程为 ,完成后线程会引用该变量副本,当同一线程
多次重复对字段赋值时,比如:
代码:
!!
!!
线程有可能只对工作内存中的副本进行赋值,只到最后一次赋值后才同步到主存储区,所以
、、 顺序可以由 实现系统决定。假设有一个共享变量 ",线程 执行 ""!。从
上面的描述中课可以知道 ""! 并不是一个原子操作,它的执行过程如下:
从主存中读取变量 " 副本到工作内存
给 " 加
讲 " 加 后的值写回主存
如果另外一个线程 # 执行 "",执行过程如下:
从主存中读取变量 " 副本到工作内存
给 " 减
将 " 减 后的值写回主存
那么显然,最终的 " 的值是不可靠的。假设 " 现在为 ,线程 加 ,线程 # 减 ,从表面上看,
似乎最终 " 还是为 ,但是多线程情况下会有这样的情况发生:
线程 从主存读取 " 副本到工作内存,工作内存中 " 的值为
线程 # 从主存读取 " 副本到工作内存,工作内存中 " 的值为
线程 将工作内存中 " 加 ,工作内存中 " 为 $
% 线程 将 " 提交到主存中,主存中 " 为
& 线程 # 将工作内存中 " 减 ,工作内存中 " 为 '$
( 线程 # 将 " 提交到主存中,主存中 " 为 '
同样," 有可能为 ,如果 " 是一个银行账户,线程 存款,线程 # 扣款,显然这样是有严重问
题的,要解决这个问题,必须保证线程 和线程 # 是有序执行的,并且每个线程执行的加 和
减 是一个原子操作。
)#****+
)#*
)#***#*+
,#*#*
-
)#*.*+
#*
-
)#*+
#*#*!
-
)#*,+
#*#*
-
)#**/01,2)3"*)+
******
4,4,4,**$$55
4,#4,6,4,**$$5,5
#
#
/7)**.*
-
**4,)8#+
****
)#*4,****$+
,****
,
-
)#*+
!!+
**
-
-
-
-
**6,4,)8#+
****
)#*6,4,****+
,****
,
-
)#*+
!!+
**,
-
-
-
第一次执行的结果是 ,第二次执行的结果是 (,每次执行的结果都是不确定的,因为
线程的执行顺序是不可预见的。这是 同步产生的根源。7*,9 关键字保证了多个线
程对于同步块是互斥的,7*,9 作为一种同步手段,解决 多线程的执行的有序性和
内存可见性,而 关键字只解决多线程的内存可见性问题。
synchronized 关键字
上面说了, 用 7*,9 关键字作为多线程并发环境的执行有序性的保证手段之一。当一段代
码会修改共享变量,这一段代码成为互斥区或临界区,为了保证共享变量的正确性, 7*,9 标志了
临界区。典型的用法如下:
7*,9锁+
临界代码
-
为了保证银行账户的安全,可以操作账户的方法如下:
)#*7*,9+
#*#*!
-
)#*7*,9,+
#*#*
-
刚才不是说了 7*,9 的用法是这样的吗:
7*,9锁+
临界代码
-
那么对于 )#*7*,9这种情况,意味着什么呢?其实这种情况,锁就是这
个方法所在的对象。同理,如果方法是 )#*7*,9,那么锁就是这个方法所在
的 *。
理论上,每个对象都可以作为锁,但一个对象作为锁时,应该被多个线程共享,这样显得有意
义,在开发环境下,一个没有共享的对象作为锁是没有任何意义的。
例如:
)#**4,4+
)#*+
:#**;:#*
7*,9*;+
<<,
-
-
-
*; 变量作为一个锁存在根本没有意义,因为它根本不是共享对象,每个线程进来都会执行
:#**;:#*每个线程都有自己的 *;,根本不存在锁竞争。
每个锁对象都有两个队列,一个是就绪队列,一个是阻塞队列,就绪队列存储了将要获得锁的
线程,阻塞队列存储了被阻塞的线程,当一个线程被唤醒7后,才会进入到就绪队列,等待 *)
的调度。当一开始线程 第一次执行 ** 方法时, 会检查锁对象 ** 的就绪队列是否
已经有线程在等待,如果有则表明了 ** 的锁已经被占用了,由于是第一次执行,** 的就绪
队列为空,所以线程 获得了锁,执行 ** 方法。如果恰好在这个时候,线程 要执行
**, 方法,因为线程 已经获得了锁还没有释放,所以线程 # 要进入 ** 的就绪队列,
等到得到锁后才可以执行。
一个线程执行临界区代码过程如下:
获得同步锁
清空工作内存
从主存拷贝变量副本到工作内存
% 对这些变量计算
& 讲变量从工作内存写会到主存
( 释放锁
可见,7*,9 既保证了多线程的并发有序性,又保证了多线程的内存可见性。
生产者/消费者
生产者<消费者模式其实是一种很经典的线程同步模型,很对时候,并不是光保证多个线程对某
共享资源操作的互斥性就可以了,往往多个线程之间都是有协作的。
假设有这样一种情况,有一个桌子,桌子上面有一个盘子,盘子里只能放一颗鸡蛋, 专门往
盘子里放鸡蛋,如果盘子里有鸡蛋,则一直等到盘子里没有鸡蛋,. 专门从盘子里拿鸡蛋,如果盘子里没
有鸡蛋,则等待直到盘子里有鸡蛋。其实盘子就是一个互斥区,每次往盘子里放鸡蛋应该都是互斥的,
的等到其实就是主动放弃锁,. 等待时还要提醒 放鸡蛋。
很简单,调用锁的 方法就好。6 方法是从 :#* 来的,所以任意对象都有这个方法。
:#**;:#*
7*,9*;+
#*#*
<<这里放弃了同步锁,好不容易得到,又放弃了
=*;
-
如果一个线程获得了锁,进入了同步块,执行 *;,那么这个线程会进入到 *; 的阻塞
队列。如果调用 *;7则会通知阻塞队列的某个线程进入就绪队列。
声明一个盘子只能放一个鸡蛋。
importjava.util.ArrayList;
importjava.util.List;
publicclassPlate{
List<Object>eggs=newArrayList<Object>();
publicsynchronizedObjectgetEgg(){
if(eggs.size()==0){
try{
wait();
}catch(InterruptedExceptione){
}
}
Objectegg=eggs.get(0);
eggs.clear(); //清空盘了
notify(); //唤醒阻塞队列的某线程到就绪队列
System.out.println("拿到鸡蛋");
returnegg;
}
publicsynchronizedvoidputEgg(Objectegg){
if(eggs.size()>0){
try{
wait();
}catch(InterruptedExceptione){
}
}
eggs.add(egg); //往盘子里放鸡蛋
notify(); //唤醒阻塞队列的某线程到就绪队列
System.out.println("放入鸡蛋");
}
}
publicclassAddThreadextendsThread{
privatePlateplate;
privateObjectegg=newObject();
publicAddThread(Plateplate){
this.plate=plate;
}
publicvoidrun(){
for(inti=0;i<5;i++){
plate.putEgg(egg);
}
}
}
剩余63页未读,继续阅读
nyq1999
- 粉丝: 3
- 资源: 5
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- zigbee-cluster-library-specification
- JSBSim Reference Manual
- c++校园超市商品信息管理系统课程设计说明书(含源代码) (2).pdf
- 建筑供配电系统相关课件.pptx
- 企业管理规章制度及管理模式.doc
- vb打开摄像头.doc
- 云计算-可信计算中认证协议改进方案.pdf
- [详细完整版]单片机编程4.ppt
- c语言常用算法.pdf
- c++经典程序代码大全.pdf
- 单片机数字时钟资料.doc
- 11项目管理前沿1.0.pptx
- 基于ssm的“魅力”繁峙宣传网站的设计与实现论文.doc
- 智慧交通综合解决方案.pptx
- 建筑防潮设计-PowerPointPresentati.pptx
- SPC统计过程控制程序.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功