并发编程学习---多线程学习流程

目录

  • 为什么要用多线程
  • 如何实现多线程
  • 使用多线程带来哪些问题
  • 如何解决
  • 底层实现

1. 为什么要用多线程

多线程出现的目的:让程序运行更快
  • 需要等待网络、I/O响应导致耗费大量的执行时间,可以采用异步线程的方式来减少阻塞
  • 通过多线程达到并行执行,提升效率

2. 如何实现多线程

  • 多线程:Thread、Runable、Callable\Funture
  • 线程池:Executor框架

具体实现参考 多线程的实现及状态说明

3. 多线程带来的问题

  • 原子性
  • 可见性
  • 有序性

3.1 原子性

当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中

 i = i + 1

当线程执行这个语句时,会先从主存当中读取i的值,然后复制一份到高速缓存当中,然后CPU执行指令对i进行加1操作,然后将数据写入高速缓存,最后将高速缓存中i最新的值刷新到主存当中
原子性带来的问题可以参考 双重检查锁定与延迟初始化

3.2 可见性

每条线程还有自己的工作内存,线程的工作内存中保存了该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量,不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。详情参考 JMM及内存操作

3.3 有序性

在不改变程序执行结果的前提下,编译器和处理器为了优化程序性能而对指令序列进行重新排序。详情参考 重排序

4. 如何解决

  • 原子性
    在java中提供了两个高级的字节码指令monitorenter和monitorexit,在Java中对应的Synchronized来保证代码块内的操作是原子的
  • 可见性
    volatile、synchronized、final
  • 有序性
    volatile、synchronized

5. 底层实现

5.1 Monitor:解决原子性

JVM基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不一样。代码块同步是使用monitorenter和monitorexit指令实现的,而方法同步是使用另外一种方式实现的,细节在JVM规范里并没有详细说明。但是,方法的同步同样可以使用这两个指令来实现。

monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处,JVM要保证每个monitorenter必须有对应的monitorexit与之配对。任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获得对象的锁
参考文档:Java并发机制的底层实现原理

5.2 内存屏障:解决可见性和有序性

内存屏障(Memory Barrier,或有时叫做内存栅栏,Memory Fence)是一种CPU指令,用于控制特定条件下的重排序和内存可见性问题。Java编译器也会根据内存屏障的规则禁止重排序。主要有三大类:读屏障、写屏障、全屏障

参考:内存屏障


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值