Java并发编程学习笔记

Java并发机制的底层实现原理

零、JMM

1. JMM是什么

java内存模型(Java Memory Model,JMM)是java虚拟机规范定义的,用来屏蔽掉java程序在各种不同的硬件和操作系统对内存的访问的差异,这样就可以实现java程序在各种不同的平台上都能达到内存访问的一致性。为了实现了JVM的跨平台性,在向上提供了一系列的指令的同时,也提供了一些编程规则需要理解和遵守,比如Happens-Before原则,as-if-serial原则,主内存工作内存的概念等等。

Happens-Before
1. 程序次序规则:

在一个线程内一段代码的执行结果是有序的。就是还会指令重排,但是随便它怎么排,结果是按照我们代码的顺序生成的不会变!

2. 管程锁定规则:

就是无论是在单线程环境还是多线程环境,对于同一个锁来说,一个线程对这个锁解锁之后,另一个线程获取了这个锁都能看到前一个线程的操作结果!(管程是一种通用的同步原语,synchronized就是管程的实现)

3. volatile变量规则:

就是如果一个线程先去写一个volatile变量,然后一个线程去读这个变量,那么这个写操作的结果一定对读的这个线程可见。

4. 线程启动规则:

在主线程A执行过程中,启动子线程B,那么线程A在启动子线程B之前对共享变量的修改结果对线程B可见。

5. 线程终止规则:

在主线程A执行过程中,子线程B终止,那么线程B在终止之前对共享变量的修改结果在线程A中可见。

6. 线程中断规则:

对线程interrupt()方法的调用先行发生于被中断线程代码检测到中断事件的发生,可以通过Thread.interrupted()检测到是否发生中断。

7. 传递规则:

这个简单的,就是happens-before原则具有传递性,即A happens-before B , B happens-before C,那么A happens-before C。

8. 对象终结规则:

这个也简单的,就是一个对象的初始化的完成,也就是构造函数执行的结束一定 happens-before它的finalize()方法。

as-if-serial

as-if-serial语义的意思是:不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。但依然会对毫无关联的两个语句进行指令重排,比如 int a=1; int b = 2; 它们的先后顺序可能会不一样.

主内存和工作内存

JMM定义的内存变量的访问规则(这里的变量是指线程共享的变量),有了主内存和工作内存的概念。 Java虚拟机规定所有变量(非线程私有的变量)都存在主内存中,而线程私有的局部变量存在线程独有的工作内存中,这两个概念比较类似Java内存规范中的堆(主内存)和虚拟机栈(工作内存),只是比较类似!

解决主内存的中的变量和工作内存中的变量的同步的方式就是用volatile关键字。

一、Volatile关键字

  • 作用:

    • 保证了“共享变量”在多线程环境下的“可见性”.
  • 底层实现原则:

    • 对被volatile修饰的变量进行写操作的时候,JVM会向处理器发送一条#Lock前缀指令,这个指令的作用就是将对应缓存行的数据写回到被缓存的内存。
    • 一个处理器将缓存回写到内存<addr>中,那么其他处理器中对<addr>内存地址的缓存都会被标记成’失效’。(缓存一致性协议MESI:由嗅探技术实现,每个缓存行会有一个标示位,分别代表 :M(被修改),E(独占的), S(共享的), I(无效的), 若读取的缓存行是无效,那么会重新从内存读取)

二、Synchronized关键字

1. 作用:

对于 Synchronized 关键字而言,每一个Java对象都可以作为锁,具体表现为:

  • 普通Synchronized方法,锁是当前对象
  • 静态Synchronized方法,锁是当前类的Class对象
  • 对于Synchronized方法块,锁是括号里配置的对象

2. 对象头:

  • 普通对象的对象头占2个字,分别为:
    • Mark Word:存储了对象的HashCode和锁信息
    • Class Metadata Address:存储对象类型的数据指针
  • 数组类对象的对象头占3个字,除了上面两个还有一个:
    • Array Length: 数组的长度
Mark Word:

在这里插入图片描述
在这里插入图片描述

3. 锁的升级和对比:

https://www.cnblogs.com/pomer-huang/p/10965228.html
在这里插入图片描述
在讲重量级锁的调用的时候,可以说一下Java对管程的实现,即每一个对象都可以被视作一个MonitorObject,且维护着一个WaitSet,EntrySet,具体可以看 这个
在这里插入图片描述

4. 原子操作的实现:

  • 处理器实现院子操作:
    • 1.总线锁:
      • 处理器提供一个LOCK #信号,当一个处理器在总线上输出此信号时,其他处理器的请求将会被阻塞,此时处理器可以独享内存。缺点是,内存的不同地址之间其实不存在同步关系,这样会使得效率很低.
    • 2. 缓存锁
      • 利用缓存一致性协议(如MESI协议),和处理器提供的LOCK指令对指定内存上锁,完成了对共享资源操作的互斥。
      • 需要注意的是以下两个情况不能使用缓存锁:
        1. 数据无法写入到缓存中,或操作数据跨多个缓存行。
        2. 处理器不支持缓存锁,此时会使用总线锁.
    • Java实现原子操作:
      • CAS操作 ( Compare And Swap )
    通过调用处理器提供的CMPXCHG指令信实现,CAS的作用是:相等则交换。
    • CAS遇到的三大问题和解决方法:
      • ABA问题

        • 问题:CAS会先检查操作值是否发生变化,如果发生了A->B->A这种变化则发现不出来。
        • 解决方法:通过增加版本号的方式来解决: 1A->2B->3A
      • 循环时间开销大:

        • 问题:在循环尝试CAS时,会给CPU带来很大的执行开销。
        • 解决方法:如果jvm能支持处理器提供的pause指令,那么效率会有一定的提升。pause指令可以延迟CPU的执行并且不会因此清空cpu的指令流水的预读取。
      • 问题:只能保证一个共享变量执行原子操作:

      • 解决方法:将多个共享变量打包成一个就行了。从JDK1.5开始,JDK提供了AtomicReference类来保证引用对象的原子性!

三、ReentrantLock与AQS

Java内存模型

1. Happens-Before原则:

编译器,处理器进行不同层次上的指令重排会对多线程编程造成一定的影响,对于一些不应该进行指令重排的场景下,Java编译器通过在适当的位置插入内存屏障指令来禁止特定类型的处理器重排序,JMM把内存屏障指令分为如下四类:
在这里插入图片描述
从JDK5开始,Java使用新的JSR-133内存模型,其主要作用就是提供了happens-before原则,屏蔽掉了底层解决内存可见行问题的实现,编程者只要记住happens-before原则,并在理解这一原则下进行编程,happens-before原则为:

  • 程序顺序原则:一个线程中的每个操作,都happens-before于该线程中的任意后续操作;
  • 监视器锁规则:对一个锁的解锁,一定happens-before于随后对这个锁的读
  • volatile变量规则:对一个volatile域的,happens-before于任意后续对这个volatile域的.
  • 传递性:A happens-before B, B happens-before C, 那么 A happens-before C.

2. as-if-serial语义

对于单线程而言,如果操作之间不存在数据依赖,且改变顺序后不对最终结果产生影响,那么会对其进行指令重排.

  • 例如:
int a = 1;
bool k = true;

这一重排尽管不会改变其对单线程的执行,但可能会导致多线程的执行结果, 因此一定要记住这个!

  • 存疑的ps: 在32位系统的JVM中,写一个64位的long long会被分成两个32位的原子操作! Java语言规范鼓励但不强求JVM对64位的long long 型变量和double变量的写操作具有原子性.

琐碎知识点:

1. 信号量和条件变量的区别是什么?

  • 条件变量可以通过signal()唤醒队首阻塞线程,使用signalAll()来唤醒所有阻塞线程;而信号量只能通过release()唤醒队首阻塞线程.
  • 信号量可以初始化初始的值,但条件变量不可以,但条件变量+共享变量可以实现初始值大于0的信号量的功能。(个人理解成,条件变量的功能类似一个初始值为0的信号量 )。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值