<返回更多

多线程场景下编码的一些思考

2020-06-30    
加入收藏

背景

编写一个单例的实现。这里采用一个双重检查方式。

多线程场景下编码的一些思考

image.png

发现是有问题的。主要是编译优化导致new 对象的顺序和可见性问题。

问题修复 :只需要再单例对象 加上 volatile 修饰即可。

分析背后的原因

多线程编程中主要核心关注如下三个点 :

可见性

缓存带来的原子性 (硬件的坑)

原子性

线程切换带来的原子性

有序问题

编译优化,内存模型一般原则(HAppens-Before)

多线程场景下编码的一些思考

image.png

这里给出一个volatile 修饰的对象 new 对象在编译后的执行字节码流程,可以看出没有做编译优化和顺序重排。

JAVA并发常见的内存模型

valatile :禁

这条规则是指一个valatile 变量的写操作

Happens-Before 于后续对这个 valatile变量的读操作

le变量的读操作

final :

编译优化更好点 ,生而不变,可以使劲的优化

传递性:

 

Happens-Before: 前面的操作结果对后续的操作是可见的

x = 7 y = 8 在多线程中,

传递性 是指 :

线程A:写 X =7 Y =8 成功

线程B:如果读到 y = 8 ,

那么他读到的X 肯定是7

Java 采用的是管程技术,synchronized 关键字及 wait()、notify()、notifyAll() 这三个方法都是管程的组成部分。

而管程和信号量是等价的,所谓等价指的是用管程能够实现信号量,也能用信号量实现管程。但是管程在利用OOP的封装特性解决了信号量在工程实践上的复杂性问题,因此java采用管理机制。

因此java

就是将共享变量及其对共享变量的操作统一封装起来。在下图中,管程 X 将共享变量 queue 这个队列和相关的操作入队 enq()、出队 deq() 都封装起来了;线程 A 和线程 B 如果想访问共享变量 queue,只能通过调用管程提供的 enq()、deq() 方法来实现;enq()、deq() 保证互斥性,只允许一个线程进入管程。管程模型和面向对象高度契合的。

多线程场景下编码的一些思考

image.png

管程如何解决线程间的同步问题呢?

Java 参考了 MESA 模型,语言内置的管程(synchronized)对 MESA 模型进行了精简。MESA 模型中,条件变量可以有多个,Java 语言内置的管程里只有一个条件变量。具体如下图所示。

多线程场景下编码的一些思考

image.png

JAVA SDK并发包通过Lock 和Condition两个接口’又’实现了一次管程。LOCK 解决互斥,Condition解决同步问题

重复造轮子

1.能够响应终端

2.支持超时

3. 非阻塞获取锁

多线程场景下编码的一些思考

image.png

轮子的理由:

1.能够响应终端

2.支持超时

先找到一个 阻塞的线程 看执行栈信息

多线程场景下编码的一些思考

image.png


多线程场景下编码的一些思考

image.png

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>