内存模型与多线程技术.ppt

上传人:本田雅阁 文档编号:2583464 上传时间:2019-04-12 格式:PPT 页数:48 大小:265.51KB
返回 下载 相关 举报
内存模型与多线程技术.ppt_第1页
第1页 / 共48页
内存模型与多线程技术.ppt_第2页
第2页 / 共48页
内存模型与多线程技术.ppt_第3页
第3页 / 共48页
亲,该文档总共48页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《内存模型与多线程技术.ppt》由会员分享,可在线阅读,更多相关《内存模型与多线程技术.ppt(48页珍藏版)》请在三一文库上搜索。

1、java内存模型与多线程技术,yangjsalibaba-,主要内容和目的,学习java多线程理论基础:JMM(java内存模型) 学习java多线程技术基础:理解同步是如和工作 分析程序什么时候需要同步 澄清对volatile误解,正确使用 Task Cancellation and Thread Shutdown策略 Lazy initialization Safety技术,JMM(java内存模型),什么是Java内存模型 Java内存模型相关概念 java线程和内存交互行为定义 Ordering&visibility JMM相关java语言规范,内存模型,操作平台的内存模型 寄存器,C

2、PU缓存,物理内存,虚拟内存 缓存一致性模型 顺序一致性模型:要求对某处理机所写的值立即进行传播,在确保该值以被所有处理机接受后才能继续其他指令的执行 释放一致性模型:允许将某处理机所写的值延迟到释放锁时进行传播,Java内存模型(JMM),内存存管理的跨平台统一的模型 write-once, run-anywhere concurrent applications in Java 定义了Java线程和内存交互的规则 通过一组语义规则来描述尤其是多线程之间共享内存的模式,保证多线程程序结果的可预测,语义一致 性 不同于其他语言,同平台无关 所有的实例变量,静态变量和数组元素都存放在堆内存里 线

3、程本地变量在堆栈中,不受JMM影响,Java内存模型相关概念,Thread working copy memory 在java规范中这是一个抽象的概念,对应可能会是寄存器,cpu缓存,编译及执行优化等 。 一个新产生的Thread有一个空的working memory。 类似一个高速缓存 线程之间无法相互直接访问,变量传递均需要通过主存完成 The main memory 就是我们所说的java堆内存 Threads execution engine 保证线程的正确执行顺序,java线程和内存交互行为定义,JLS中对线程和主存互操作定义了6个行为,分别为load,save,read,write

4、,assign和use,这些操作行为具有原子性,且相互依赖,有明确的调用先后顺序 A use action (by a thread) transfers the contents of the threads working copy of a variable to the threads execution engine. An assign action (by a thread) transfers a value from the threads execution engine into the threads working copy of a variable. A read

5、 action (by the main memory) transmits the contents of the master copy of a variable to a threads working memory for use by a later load operation. A load action (by a thread) puts a value transmitted from main memory by a read action into the threads working copy of a variable. A store action (by a

6、 thread) transmits the contents of the threads working copy of a variable to main memory for use by a later write operation. A write action (by the main memory) puts a value transmitted from the threads working memory by a store action into the master copy of a variable in main memory.,java线程和内存交互分析

7、,例子分析: class Simple int a = 1, b = 2; /Thread 1 executes void to() a = 3; b = 4; /Thread 2 executes void fro() System.out.println(“a= “ + a + “, b=“ + b); 类似计算机多级存储器结构,Working Memory类似Cache机制 问题:变量a,b何时写会main memory?,Ordering&visibility,程序顺序: 程序声明它们应当发生的顺序 执行顺序:JMM不保证线程对变量操作发生的顺序和被其他线程看到的是同样的顺序。 JMM

8、容许线程以写入变量时所不相同的次序把变量存入主存 线程内部本身遵循程序顺序,从线程外看到的是执行顺序 编译器和处理器可能会为了性能优化,进行重新排序 程序执行为了优化也可能重新排序,Ordering&visibility,多线程场景分析 class Simple int a = 1, b = 2; /Thread 1 executes void to() a = 3; /This can appear to happen second b = 4; / This can appear to happen first /Thread 2 executes void fro() System.ou

9、t.println(“a= “ + a + “, b=“ + b); 下面哪种结果是正确的: a=1, b=2 a=1, b=4 a=3, b=2 a=3 ,b=4,Happens-Before Memory Model,类似释放一致性模型 Partial ordering(happens-before) :如果B能够看到A动作产生的结果,我们说A happens-before B,JMM定义了一些这样的规则,如: Program order rule. Each action in a thread happens-before every action in that thread tha

10、t comes later in the program order. Monitor lock rule. An unlock on a monitor lock happens-before every subsequent lock on that same monitor lock. Volatile variable rule. A write to a volatile field happens-before every subsequent read of that same field ,The rules for happens-before,JMM相关java语言规范,J

11、MM定义了保证内存操作跨线程的正确的Ordering和visibility 方法 Java语言提供的技术和工具 synchronized 块 volatile 变量(在JDK5+的JVM中得到修补) 工具类:java.util.concurrent.locks 原子变量java.util.concurrent.atomic Final变量(在JDK5+的JVM中得到修补),正确的理解synchronized,synchronized 作用说明 Synchronized内存模型语义分析 如何判定多线程的程序何时需要Synchronized 同步需求的JMM内存交互分析练习 锁对象的引用在同步块中

12、发生修改会出现什么? Hostspot JVM的synchronized优化技术 直接使用synchronized 不足之处,synchronized 作用说明,Low level locking 什么时候需要synchronized ? 一个变量有可能被多个线程访问,其中至少有一个线程是写操作 每个对象都有一个相关的lock对象(监视器) java语言没有提供分离的lock和unlock操作 ,但是在JVM提供了两个单独的指令monitorenter和monitorext来实现 特性 Atomicity :Locking to obtain mutual exclusion Visibili

13、ty :Ensuring that changes to object fields made in one thread are seen in other threads(memory) Ordering: Ensuring that you arent surprised by the order in which statements are executed Blocking:Cant interrupt,Synchronized内存模型语义分析,Synchronized:通过对象引用找到同步对象,然后获取对象上的监视器进行锁操作 当线程进入synchronized 块之后首先要做的

14、是清洗 threads working memory, 对块内使用到的变量要么执行assign动作要么对use的变量执行 read-load原子操作从 main memory装载新的值 当线程退出synchronized 块之前,对它在working memory中所有的 assigned values执行 store write原子操作,写回main memory,Synchronized内存模型语义分析,Example: / block until obtain lock synchronized(obj) / get main memory value of field1 and fie

15、ld2 int x = obj.field1; int y = obj.field2; obj.field3 = x+y; / commit value of field3 to main memory / release lock,如何分析多线程并发需求,class SynchSimple int a = 1, b = 2; /Thread 1 executes synchronized void to() a = 3; b = 4; /Thread 2 executes void fro() System.out.println(“a= “ + a + “, b=“ + b); 以下哪种结

16、果是正确的? a=1, b=2 a=1, b=4 a=3, b=2 a=3 ,b=4 这是一个线程安全的类吗? 接下来我们通过JMM语义来分析这个例子,JMM内存交互分析,JMM内存交互分析,SynchSimple 分析: write a 和 write b 在synchronized 规则中并没有规定发生的顺序约束 read a 和 read b. 同样也没有规定发生的顺序 结果说明的什么问题? 对一个方法声明synchronized 并不能够保证这个方法行为产生的结果是一个原子操作,也就是说write a 和 write b 两个操作在main memory不是原子行为,虽然单个都是原子操

17、作。,下面我们做一个练习:,JMM内存交互分析练习,Example: class Foo int a = 1, b = 2; synchronized void to() a = 3; b = 4; synchronized void fro() System.out.println(“a= “ + a + “, b=“ + b); 分析结果是什么?,问题?,这个方法的同步块有可能被多个线程并发执行! 有可能在intArr.length size的条件下获得两把不同的锁,锁对象的引用在同步块中发生修改会出现什么? public void foo(int isze) synchronized(i

18、ntArr) if(intArr.length size) int newIntArr = new intsize; System.arraycopy(intArr,0,newIntArr,0,intArr.length); intArr = newintArr; ,直接使用synchronized 不足之处和发展,不能够扩越多个对象 当在等待锁对象的时候不能中途放弃,直到成功 等待没有超时限制 Thread.interrupt()不能中断阻塞 JDK5中提供更加灵活的机制:Lock和Condition synchronized在JDK6中性能将会有很大提升,Hostspot JVM的sync

19、hronized优化技术,锁省略:锁对象的引用时线程本地对象(线程的堆栈内的对象) public String getStoogeNames() Vector v = new Vector(); v.add(“Moe“); v.add(“Larry“); v.add(“Curly“); return v.toString(); ,Hostspot JVM的synchronized优化技术,锁粗化:锁粗化就是把使用同一锁对象的相邻同步块合并的过程 public void addStooges(Vector v) v.add(“Moe“); v.add(“Larry“); v.add(“Curly

20、“); ,Hostspot JVM的synchronized优化技术,自适应锁优化技术 实现阻塞有两种的技术,即让操作系统暂挂线程,直到线程被唤醒,或者使用旋转(spin) 锁。旋转锁基本上相当于以下代码: while (lockStillInUse) ; Hotspot JVM可以对持有时间短的锁使用旋转,对持有时间长的锁使用暂挂。,理解和使用Volatile变量,Volatile变量的内存模型分析 使用valatile JDK5的util.concurrent.atomic,Volatile变量的内存模型分析,“不要相信volatile ”,这种说法已经过时 旧的内存模型:保证读写vola

21、tile都直接发生在main memory中,线程的working memory不进行缓存 仅仅保证这些volatile使用的价值和意义不大 在新的内存模型下对volatile的语义进行了修补和增强 如果当线程 A 写入 volatile 变量 V 而线程 B 读取 V 时,那么在写入 V 时,A 可见的所有变量值现在都可以保证对 B 是可见的。结果就是作用更大的 volatile 语义,代价是访问 volatile 字段时会对性能产生了一点点的影响。(A volatile var write happens-before read of the var),Volatile变量的内存模型分析,

22、volatile 的旧语义只承诺正在读和写的变量的可见性,仍然参与排序。这样导致排序问题。新的内存模型修补了这一点 实际上,对 volatile 字段的每一次读或者写都像是“半个”同步。 对 volatile 的读有与monitor enter的内存语义, 对 volatile 的写有与monitor exit的同样的语义。,Volatile Guarantees Visibility,Stop 用volatile修饰来保证变量的写可见性 class Task implements Runnable private volatile boolean stop = false; public v

23、oid stop() stop = true; public void run() while (!stop) runTask(); try Thread.sleep(100); ; private void runTask() /*.*/ ,Volatile Guarantees Ordering,If a thread reads data, there is a happens-before edge from write to read of ready that guarantees visibility of data (A volatile ready write happens

24、-before read of the ready),使用valatile,volatile 变量+操作不是原子行为 volatile int x= 1; x+;/不是一个原子操作,需要多条指令 Volatile 变量比 synchronization要便宜很多 在jdk5中推荐采用 util.concurrent.atomic 工作机制类似Volatile 同时提供了简单运算的原子行为,JDK5的util.concurrent.atomic,get() 具有读取 volatile 变量的内存效果。 set() 具有写入(分配) volatile 变量的内存效果 支持操作: getAndSet

25、 getAndAdd addAndGet getAndDecrement getAndIncrement decrementAndGet incrementAndGet 只要你有足够的能力,用Atomic变量能够实现所有的同步,Cancellation and Shutdown,Cancellation and Shutdown Task cancellation policy 设计 Cancellation policy :Interruption 正确处理InterruptedException,Cancellation and Shutdown,clean up any work the

26、n terminate.(Safe terminate) 为什么需要cancellable (中断正在进行的活动) User-requested cancellation Time-limited activities Application events Errors Shutdown 安全快速可靠结束一个线程是一个比较复杂的话题 Java没有提供安全的强迫一个Thread结束的方法 Java provides interruption, a cooperative mechanism,cancellation policy 设计,How: how other code can reques

27、t cancellation When:when the task checks whether cancellation has been requested What:what actions the task takes in response to a cancellation request.,Example: cancellation policy 设计,class Task implements Runnable private volatile boolean stop = false; public void stop() stop = true; public void r

28、un() while (!stop) runTask(); try Thread.sleep(100); ; private void runTask() /*.*/ ,Example: cancellation policy 设计分析,How,When,How? 问题: polling loops,只有一个检查点 线程不能立刻结束,要等到检测的时候 遇到Blocking method有可能无法中止 检查的变量必须是volatile修饰的,Cancellation policy :Interruption,礼貌地劝告另一个线程在它愿意并且方便的时候停止它正在做的事情。(Interruption

29、 is a cooperative mechanism ) Thread中断状态(interrupted status):线程的一个内部属性,类型:boolean,初始值:false. Thread.interrupt():设置interrupted status 为true,interruption Policy 分析,分析: How:Thread.interrupt()方法. interrupt() 只是设置线程的中断状态。表示当前线程应该停止运行。 When:在 Thread.sleep()、 Thread.join() 或 Object.wait()等方法中取消阻塞并抛出 Interr

30、uptedException,也可以程序检测: 轮询中断状态:Thread.isInterrupted() 读取并清除:Thread.interrupted() InterruptibleChannel (java.nio):Most standard Channels implement InterruptibleChannel 等待获取文件锁定时可以被另一个线程中断,Cancellation policy :Interruption,Interruption is usually the most sensible way to implement cancellation 其他问题 不能

31、打断一些IO操作,比如文件操作 无法终止在synchronized块上锁住的Thread Synchronous socket I/O in java.io,InterruptedException,检查型异常:java.lang.InterruptedException 当线程在很长一段时间内一直处于正在等待、休眠或暂停状态(Object.wait(), Object.wait(long), Object.wait(long, int), Thread.sleep(long)),而另一个线程用 Thread 类中的 interrupt 方法中断它时,抛出该异常。 阻塞(blocking)方法

32、 方法签名包括抛出 InterruptedException,调用一个阻塞方法则意味着这个方法也是一个阻塞方法 当中断阻塞方法时,抛出InterruptedException Thread 在 Thread.sleep() 和 Object.wait() 等方法中支持的取消机制,表明可以提前返回。 当一个阻塞方法检测到中断并抛出 InterruptedException 时,它清除中断状态,如何处理InterruptedException,错误的做法:swallow interruption requests try Task task = queue.take(); task.execute

33、(); catch (InterruptedException e) log.error(); ,如何处理InterruptedException,Restore the interrupt 如果真的要湮灭InterruptedException,应该保留被别人中断的证据,交给高层去决定。 /恰当的做法: try Task task = queue.take(); task.execute(); catch (InterruptedException e) log.error(); Thread.currentThread().interrupt(); Propagate the Interr

34、uptedException 重新抛出它 ,如果抛到顶层,可以结束当前线程,Double-Checked Locking,目的:在多线程应用中用来lazy initialization并保证Singlen 在java语言中DCL不成立 / Broken multithreaded version / “Double-Checked Locking“ idiom class Foo private Helper helper = null; public Helper getHelper() if (helper = null) synchronized(this) if (helper = n

35、ull) helper = new Helper(); return helper; / other functions and members. ,为什么在java语言中DCL不成立,Java 构造对象不是原子操作: 先申请一块空内存 将其地址赋予 对象引用 在对象引用所指的地址之上构建对象,调用构造函数初始化 很多人提供了很多方法来修复DCL,但是没有人能够成功 行为正确的程序,但是增加了同步的负担 / Correct multithreaded version ,but synchronized every time! class Foo private Helper helper =

36、null; public synchronized Helper getHelper() if (helper = null) helper = new Helper(); return helper; / other functions and members. ,Initialize-On-Demand Holder Class idiom,private static class LazySomethingHolder public static Something something = new Something(); . public static Something getInstance() return LazySomethingHolder.something; ,几点建议,开发多线程系统一定要理解java的内存模型,那样你才能够正确地分析线程需求 尽量使用现成的解决方案,util.concurrent 优化的前提是保证程序的正确性,其次才是提高程序的性能 缩小锁的作用范围 缩短锁的存在时间,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1