Java线程之间的通信采用的是共享内存模型,而java内存模型是用来控制java线程通信的,抽象的说:java内存模型定义了线程和主内存的抽象关系,线程间的共享变量存储在主内存,每个线程都有一个私有的工作内存,用来存储该线程使用到的共享内存中变量的副本,工作内存是一个抽象概念它涵盖了缓存、写缓冲区、寄存器等。
java 内存模型还定义了两项操作之间的偏序关系,也就是先行发生原则,它是用来判断数据是否存在竞争、线程是否安全的主要依据,我们可以通过几条规则一揽子解决并发环境下两个操作之间是否可能存在冲突的所有问题
·Happens-before(先行发生原则)原则:
JSR-133提出了happens-before的概念,通过这个概念来阐述操作之间的内存可见性。如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间。
先行发生原则是java 内存模型中定义的两项操作之间的偏序关系,它是用来判断数据是否存在竞争、线程是否安全的主要依据,我们可以通过几条规则一揽子解决并发环境下两个操作之间是否可能存在冲突的所有问题。
含义eg:A先行发生于B 就是说在发生B操作之前,操作A所产生的影响能被B观察到,“影响” 包括 修改了内存中共享变量的值、发送了消息、调用了方法等
原则列表:
1、程序次序规则:在一个线程内,按照代码的执行顺序(准确应该是控制流顺序,因为要考虑分支、循环等结构),书写在前面的操作先行发生于书写在后面的操作
ps: a 先行发生 b 并不意味着 a在时间上较 b先执行,因为编译器、处理器、运行时环境为了最大限度的使用计算机性能,都会对指令进行重排序,只保证最后的执行结果和顺序执行的结果一致。同理 a在时间上较b先执行也不意味着a先行发生于b,这个要判断该两项操作是否可以由先行发生原则推导出来。
2、管程锁定规则:一个unlock 操作先行发生于后面对同一个锁的lock操作,这里的后面指时间上的先后顺序 ps:要使用一个被锁定的模块儿 肯定是 先解锁操作,再执行加锁操作
3、volatile 变量规则:对一个volatile变量的写操作 先行 发生于对后面这个变量的读操作 这里的后面指时间上的先后顺序,ps:被volatile声明变量 保证内存的可见性 ,并在变量声明的前后禁止指令冲排序
4、传递性:如果A 先行发生于B,B先行发生于C,就可以得出 A 先行发生于 C.
5、线程 的启动、终止、中断规则:
启动规则:Tread 对象的start() 方法 先行发生于此线程的每一个动作
终止规则:线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法结束、Tread.isAlive()的返回值等手段检测到线程已经终止执行
终端规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断时间的发生,可以通过Thread.interrupted()方法检测到是否有中断发生
6、对象的终结规则:一个对象的初始化完成(构造函数执行结束) 先行发生于它的finalize()方法的开始。
·as-if-serial语义:
within-thread as-if-serial semantics (线程内表现为串型的语义):
无论如何重排序,单线程的执行结果不能被改变,保证对有数据依赖关系的操作会禁止指令重排序
·volatile 变量规则:
volatile是java虚拟机提供的最轻量的同步机制,当一个变量被volatile修饰后其具备两层语义:
1、保证此变量对所有线程的可见性
2、禁止指令冲排序
更多烟台培训相关资讯,请扫描下方二维码