这几天面试互联网公司的高级java工程师,多线程问的相对而言比较多。因此,从各类角度来看看java中多线程的实现方式。java
根据java内存模型,java中全部的变量都存储在主内存中(main memory),每条线程还有本身的工做内存(Working Memory),线程的工做内存中保存了主内存的副本拷贝,线程对全部变量的操做都必须在工做内存中进行而不能操做主内存的变量。不一样的线程不能访问别的线程工做内存中的变量,线程之间的变量值传递必需要经过主内存来完成,线程、主内存、工做内存三者的交互关系以下图所示:面试
java内存模型定义了8种不一样操做来完成,虚拟机实现时候必须保证这8种操做都是原子的、不可再分的。多线程
lock(锁定):主要做用于主内存变量,它把一个变量标志为一条线程独占的状态。app
unlock(解锁):做用于主内存变量,它将处于一个锁定状态的变量释放出来,释放出来的内存变量才能被其余线程锁定。this
read(读取):做用于主内存的变量,它把一个变量的值从主内存中运输到线程的工做内存中,以便随后的load指令使用。spa
laod(载入):做用于工做内存的变量,它把主内存中读到的变量放入工做内存变量的副本中。线程
use(使用):做用于工做内存中的变量,它把工做内存中的一个变量值传递给执行引擎,每当虚拟机遇到一个须要使用变量值的字节码指令时候回执行这个操做。blog
assign(赋值):做用于工做内存变量,它把一个从执行引擎接受到的值赋给工做内存中的变量,每当虚拟机遇到一个给变量赋值的字节码的时候执行这个操做。排序
store(存储):做用于工做内存中的变量,它把工做内存中的一个变量送到主内存中,以便之后的write操做使用。内存
write(写入):做用于主内存中,它把store操做从工做内存中获得的变量的值放入主内存中。
原子性:由java内存模型来直接保证原子性的操做包括read、load、assign、use、store和write。基本数据类型访问具备原子性(除了long 和double类型特殊的非原子协定)。
若是须要更大范围的原子性操做的时候,java内训模型还提供了lock()和unlock()操做来完成这种需求。在字节码层次上提供了monitorebter和moniterexit来隐式的使用这个操做,这两个字节码反映到java代码中就是同步代码块--sychronized关键字。
可见性:是指当一个线程修改了共享变量的值,其余线程可以当即得知这个修改。
java内存模型是经过变量在修改后的新值同步回主内存中,在变量读取前从主内存刷新变量值住,这种依赖 主内存做为传递媒介的方式来实现可见性的。经过volatile保证了线程之间的可见性。一样还有synchronized 和final 来实现线程可见性。
同步代码块的可见性是由“对一个变量执行unlock操做以前,必须先把此变量同步到主内存中(执行store 和 write操做)”。被final修饰的普通变量在构造器中一旦初始化完成,而且构造器没有把"this"关键字的引用传递出去,那么在其余线程中就能看见final关键字的值。
有序性:在java语言中提供了volatile和synchronized俩个关键字来保证线程之间操做是有序性,volatile关键字自己包含了禁止指令重排序的语义,而sychronized则是由“一个变量在同一时刻只容许一个线程进行lock操做”,这条规则决定了持有同一个锁的同步代码块只能串行地进入。
四、happen-before原则