写点什么

多线程问的太深入不知道怎么回答,从 volatile 开始给你讲清楚

用户头像
小Q
关注
发布于: 2020 年 11 月 17 日

volatile的用途

1.线程可见性

可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉。通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。

**可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。**也就是一个线程修改的结果。另一个线程马上就能看到。比如:用volatile修饰的变量,就会具有可见性。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。所以对其他线程是可见的。但是这里需要注意一个问题,volatile只能让被他修饰内容具有可见性,但不能保证它具有原子性。比如 volatile int a = 0;之后有一个操作 a++;这个变量a具有可见性,但是a++ 依然是一个非原子操作,也就是这个操作同样存在线程安全问题。

package com.msb.testvolatile;

public class T01_ThreadVisibility {
private static volatile boolean flag = true;

public static void main(String[] args) throws InterruptedException {
new Thread(()-> {
while (flag) {
//do sth
}
System.out.println("end");
}, "server").start();


Thread.sleep(1000);

flag = false;
}
}


2.防止指令重排序

问题:DCL单例需不需要加volatile?

CPU的基础知识

  • 缓存行对齐缓存行64个字节是CPU同步的基本单位,缓存行隔离会比伪共享效率要高Disruptor

  • 伪共享

  • 合并写CPU内部的4个字节的Buffer

  • 指令重排序

volatile如何解决指令重排序

1: volatile i

2: ACC_VOLATILE

3: JVM的内存屏障

4:hotspot实现

bytecodeinterpreter.cpp

int field_offset = cache->f2_as_index();
if (cache->is_volatile()) {
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
OrderAccess::fence();
}


orderaccess_linux_x86.inline.hpp

inline void OrderAccess::fence() {
if (os::is_MP()) {
// always use locked addl since mfence is sometimes expensive
#ifdef AMD64
__asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory");
#else
__asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");
#endif
}
}


第一次写这种底层的东西,整理了好几次话术,实在是没整明白该怎么发,因为确实有点难以整理话术,所以这里附上了关键地方的源码以及实例,运行一下可能会更好理解这些技术,后面我会去逐步改进



个人公众号:Java架构师联盟,每日更新技术好文



发布于: 2020 年 11 月 17 日阅读数: 28
用户头像

小Q

关注

还未添加个人签名 2020.06.30 加入

小Q 公众号:Java架构师联盟 作者多年从事一线互联网Java开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教程,侧重点更倾向编写Java核心内容。如果能为您提供帮助,请给予支持(关注、点赞、分享)!

评论

发布
暂无评论
多线程问的太深入不知道怎么回答,从volatile开始给你讲清楚