java 多线程知识梳理1
概念
JMM:规定了jvm有主内存(Main Memory)和工作内存(Working Memory) ,主内存存放程序中所有的类实例、静态数据等变量,是多个线程共享的,而工作内存存放的是该线程从主内存中拷贝过来的变量以及访问方法所取得的局部变量, 是每个线程私有的其他线程不能访问,每个线程对变量的操作都是以先从主内存将其拷贝到工作内存再对其进行操作的方式进行,多个线程之间不能直接互相传递数 据通信,只能通过共享变量来进行。
操作指令:JLS定义了线程对主存的操作指令:read,load,use,assign,store,write。这些行为是不可分解的原子操作,在使用上相互依赖,read-load从主内存复制变量到当前工作内存,use-assign执行代码改变共享变量值,store-write用工作内存数据刷新主存相关内容。引用http://www.cnblogs.com/fguozhu/articles/2657904.html
进程:一般作为资源的组织单位,是计算机程序的运行实例,表示正在执行的指令,有自己独立的地址空间,包含程序内容和数据,进程间资源和状态相互隔离
线程:程序的执行流程,CPU调度执行的基本单位,有自己的程序计数器,寄存器,堆栈,帧,共享同一进程的地址空间,内存和其他资源
原则性操作:cpu调度的基本单位是指令,而一段程序可能机器分解为多条指令,如i++,分为读取-修改-写入3条,线程安全的前提是保证操作原子性。CPU在一条指令的执行过程中不会进行线程调度和上下文切换,但是在两条指令的执行间隙,可能发生线程切换
线程不安全:当出现复合操作,如先检查在执行或者读取-修改-写入等包含多条指令,而不能以原子方式执行的时候,必须依赖运气(线程按恰当时序交替),否则就会出现不正确的结果。无状态对象(不包含任何域)是线程安全的
内置锁:synchronized同步代码块或者方法,是一种互斥锁,每次只能有一个线程持有。内置锁可以重入,即一个线程可以获取自己已经持有的锁,例子:
可重入锁:
可见性:使用共享内存的方式进行多线程通信的话,可能造成可见性的相关问题,即一个线程所做的修改对于其他的线程不可见,导致其他线程仍然使用错误的值。
volatile:java 的轻量级同步措施,volatile只能保证多线程的内存可见性,不能保证多线程的执行有序性。实现原理是任何被volatile修饰的变量,都不拷贝副 本到工作内存,任何修改都及时写在主存。因此对于valatile修饰的变量的修改,所有线程马上就能看到,但是volatile不能保证对变量的修改是 有序的。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
1、对变量的写操作不依赖于当前值。
2、该变量没有包含在具有其他变量的不变式中。
synchronized:可以保证可见性 有序性和原子性。实现如下
可见性:当锁被释放时,对共享变量的修改会从CPU缓存直接写回到主存中;当锁被获取时,CPU的缓存内存被置为失效状态,从主存中重新读取共享变量的值。
有序性:编译器在处理synchronized代码块的时候,不会把其中包含的代码移到synchronized之外,从而避免了由于代码重排而造成的问题。
原子性:一个线程运行执行synchronized代码块之前,需要先获取对应的监视器上的锁对象,执行完之后自动释放。保证同一时刻只有一个线程在操作同步块里头的变量。
JVM的执行步骤如下:
- 取得该对象锁(普通方法的锁为this对象,静态方法则为该类的class对象)并将其锁住(lock)。
- 将需要的数据从主内存拷贝到自己的工作内存(read and load)。
- 根据程序流程读取或者修改相应变量值(use and assign)。
- 将自己工作内存中修改了值的变量拷贝回主内存(store and write)。
- 释放对象锁(unlock)。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。