Java 多线程(原理篇)

本文有点长,请慢慢食用…(当然想更清楚还是去看上次推荐的书)

Java 内存模型(JMM)

JMM的抽象示意图:
在这里插入图片描述
由图可知:

  1. 所有的共享变量都存在主内存中。
  2. 每个线程都保存了一份该线程使用到的共享变量的副本。
  3. 如果线程A与线程B之间要通信的话,必须经历下面2个步骤:
    a. 线程A将本地内存A中更新过的共享变量刷新到主内存中去。
    b. 线程B到主内存中去读取线程A之前已经更新过的共享变量。

因为根据JMM的规定,线程对共享变量的所有操作都必须在自己的本地内存中进行,不能直接从主内存中读取。所以,线程A无法直接访问线程B的工作内存,线程间通信必须经过主内存。说人话就是:线程A操作的结果对线程B是不可见的,必须要等结果刷新回主存才变成可见的变量。

JMM通过控制主内存与每个线程的本地内存之间的交互,来提供内存可见性保证。


重排序与happens-before

计算机在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排。

指令重排一般分为以下三种:

  • 编译器优化重排
    编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
  • 指令并行重排
    现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性(即后一个执行的语句无需依赖前面执行的语句的结果),处理器可以改变语句对应的机器指令的执行顺序。
  • 内存系统重排(导致了内存可见性的问题)
    由于处理器使用缓存和读写缓存冲区,这使得加载(load)和存储(store)操作看上去可能是在乱序执行,因为三级缓存的存在,导致内存与缓存的数据同步存在时间差。

JMM提供了happens-before规则(JSR-133规范),满足了程序员的需求——简单易懂,并且提供了足够强的内存可见性保证。换言之,程序员只要遵循happens-before规则,那他写的程序就能保证在JMM中具有强的内存可见性。

JMM可以通过happens-before关系向程序员提供跨线程的内存可见性保证。happens-before关系的定义如下:

  1. 如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。
  2. 两个操作之间存在happens-before关系,并不意味着Java平台的具体实现必须要按照happens-before关系指定的顺序来执行。如果重排序之后的执行结果,与按happens-before关系来执行的结果一致,那么JMM也允许这样的重排序。

总之,如果操作A happens-before操作B,那么操作A在内存上所做的操作对操作B都是可见的,不管它们在不在一个线程。

volatile关键字呢由于本人已经挺熟悉的了,就不写了,想了解的小伙伴就自行去看书吧…


内存屏障

JVM通过内存屏障来实现限制处理器的重排序。

什么是内存屏障?硬件层面,内存屏障分两种:读屏障(Load Barrier)写屏障(Store Barrier)。内存屏障有两个作用:

  1. 阻止屏障两侧的指令重排序;
  2. 强制把写缓冲区/高速缓存中的脏数据等写回主内存,或者让缓存中相应的数据失效。(注意这里的缓存主要指的是CPU缓存,如L1,L2等)

编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。编译器选择了一个比较保守的JMM内存屏障插入策略,这样可以保证在任何处理器平台,任何程序中都能得到正确的volatile内存语义。这个策略是:

  • 在每个volatile写操作前插入一个StoreStore屏障;
  • 在每个volatile写操作后插入一个StoreLoad屏障;
  • 在每个volatile读操作后插入一个LoadLoad屏障;
  • 在每个volatile读操作后再插入一个LoadStore屏障。

synchronized与锁

synchronized底层原理

首先需要明确的一点是:Java多线程的锁都是基于对象的,Java中的每一个对象都可以作为一个锁。

我们通常使用synchronized关键字来给一段代码或一个方法上锁。它通常有三种形式:

  • synchronized在实例方法上,锁为当前实例
  • synchronized在静态方法上,锁为当前Class对象(即类模板)
  • synchronized在代码块上,锁为括号里面的对象
public void blockLock(
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值