并发编程的特性——可见性
创始人
2025-05-30 12:09:30
0

线程间的可见性

多线程为了提高效率,在线程本地缓存数据,造成数据修改线程间不可见,而被volatile修饰的内存,只要有修改,马上同步涉及到的每个线程

public class HelloVolatile {// 对比一下有无volatile的情况下,整个程序运行结果的区别private static /*volatile*/ boolean running = true;private static void m() {System.out.println("m start");while (running) {//System.out.println("hello");}System.out.println("m end!");}public static void main(String[] args) {new Thread(HelloVolatile::m, "t1").start();SleepHelper.sleepSeconds(1);running = false;}
}

在上面的代码中,running是存在于堆内存的t对象中

  • 当线程t1开始运行的时候,会把running值从内存中读到t1线程的工作区,在运行过程中直接使用这个copy,并不会每次都去读取堆内存,这样,当主线程修改running的值之后,t1线程感知不到,所以不会停止运行

  • 使用volatile,将会强制所有线程都去堆内存中读取running的值

  • volatile并不能保证多个线程共同修改running变量时所带来的不一致问题,也就是说volatile不能替代synchronized

缓存行对齐

为了提高线程缓存和内存之间数据交互的效率,所以要使用缓存行。cpu将数据加载到缓存中的最小数据单位是行,缓存中也是以缓存行为单位进行存储的

缓存行越大,局部性空间效率越高,但读取时间慢;缓存行越小,局部性空间效率越底低,但读取时间快。目前采用最多的是折中值,即64字节

缓存行的最低容量限制带来了一个问题,就是伪共享问题。位于同一缓存行的两个不同数据,被两个不同CPU锁定,产生互相影响的伪共享问题,比如xy位于同一缓存行,C1(CPU1)只用x,C2只用2,但是更新读取数据都是以整个缓存行为单位,所以即使仅仅只是改了缓存行中的一条数据,但更新的是整个缓存行,一个CPU更新缓存行之后另一个又要重新读取,这就是缓存行的伪共享

要解决这个问题,可以让x和y不在同一个缓存行里就行,这就是缓存行对齐

用一个demo来演示一下缓存行对齐和缓存一致性协议对效率的影响

public class CacheLinePadding {public static long COUNT = 10_0000_0000L;private static class T {// 7个long类型56byte,加上x正好是一个缓存行的长度private long p1, p2, p3, p4, p5, p6, p7;public long x = 0L; //8bytes// 作用同上,补齐缓存行private long p9, p10, p11, p12, p13, p14, p15;}public static T[] arr = new T[2];static {arr[0] = new T();arr[1] = new T();}public static void main(String[] args) throws Exception {CountDownLatch latch = new CountDownLatch(2);Thread t1 = new Thread(() -> {for (long i = 0; i < COUNT; i++) {arr[0].x = i;}latch.countDown();});Thread t2 = new Thread(() -> {for (long i = 0; i < COUNT; i++) {arr[1].x = i;}latch.countDown();});final long start = System.nanoTime();t1.start();t2.start();latch.await();System.out.println((System.nanoTime() - start) / 100_0000);}
}

上述代码中,两个线程分别对数组元素T对象中的x变量进行修改,如果注掉上下两行long类型的变量,当两个线程执行完时打印耗时784,而如果放开这两行代码,则耗时236,这是为什么呢?

考虑一下,如果把这两行填充代码去掉,那么arr[0].x和arr[1].x,我们暂且叫x1和x2吧,他俩大概率是位于同一缓存行的。由于上面提到的伪共享问题,t1线程只修改了x1,t2线程只修改了x2,但他们都会以整个缓存行为单位进行更新和读取,既然同一缓存行的数据在两个线程中都存在,那么势必要有某种机制,当t1线程修改完缓存行时要通知t2线程,这种机制就是缓存一致性协议。

那为什么在x前后加了无意义填充效率会高呢,因为两个线程在初始化变量x时,不管在x前面还是后面的数据都会和x组成一个完整的缓存行,这样就能保证两个线程修改各自的x时,x所在的缓存行中没有其他线程需要的数据,修改不用通知其他线程,其他线程也不用同步,省去了缓存一致性协议的要求,所以效率提高了

实际上,这种对齐方式在一些框架源码中是有运用的,如LinkedBlockingQueue及Disruptor框架中

volatile的作用

保证线程可见性

大家知道java里面是有堆内存的,堆内存是所有线程共享里面的内存,除了共享的内存之外呢,每个线程都有自己的专属的区域,都有自己的工作内存,如果说在共享内存里有一个值的话,当我们线程,某一个线程都要去访问这个值的时候,会将这个值copy一份,copy到自己的这个工作空间里头,然后对这个值的任何改变,首先是在自己的空间里进行改变,什么时候写回去,就是改完之后会马上写回去。什么时候去检查有没有新的值,也不好控制。

在这个线程里面发生的改变,并没有及时的反应到另外一个线程里面,这就是线程之间的不可见 ,对这个变量值加了volatile之后就能够保证 一个线程的改变,另外一个线程马上就能看到。

禁止指令重排序

禁止指令重排序属于线程有序性特性中的内容,下篇再聊

相关内容

热门资讯

分数到底有多重要?这是我见过最... 每一位家长都不希望培养高分低能的孩子,但也不希望培养低分高能的孩子,而是高分高能、综合能力强的孩子。...
启慧教育大型家庭教育公益讲座山... 最新或2023(历届)3月7日,中国教育学会家庭教育研究员、中国关心下一代工作委员会特聘讲师、最新或...
最新或2023(历届)中央民族... 中央民族大学(Minzu University of China)坐落于北京学府林立的海淀区,南邻国...
北京一本大学有哪些,最新或20... 以下是北京市一本大学排名:排名学校名称全国排名热门专业学校类型学校面积学校人数所在城市详细介绍1北京...
新版logcat最全使用指南 前言: 俗话说,工欲善其事,必先利其器。logcat是我们...
家园携手幼小衔接,共建孩子成长... 幼儿园生活过渡到小学生活是儿童成长过程的一个重大的转折点。如何做好幼小衔接工作,让孩子进入小学后能够...
何为“财经素养”?它的内涵和外... 1什么是财经素养?财经素养或称“财商”,都是外来词。之所以使用“财经素养”,是因为“素养”这个词更能...
为什么孩子不肯听我的? 孩子为... 孩子为什么不听你的?是孩子不认同你说的话?还是你跟孩子沟通的方式不对?”1很多家长喜欢和孩子讲道理,...
父母错误的教育方式会毁掉孩子一... 家长们必须清楚地认识到,一个人从婴儿到儿童、少年、青年再到成年,主要是家长在影响着他的成长,是家长在...
双流区最新或2023(历届)社... 为落实《教育部等九部门关于进一步推进社区教育发展的意见》《成都市社区教育促进条例》和《关于指导推进家...
PyTorch入门(七)Ten...   PyTorch模型的可视化工具: VisdomTensorBoardPytorch...
汽车电子实现车联网的几个关键模... 汽车里有好多的ECU,哪些会是实现车联网的关键模块呢?有人说肯定是车机中控IVI,因为这里可能是汽车...
最新或2023(历届)可爱的小...  我爱养了一只可爱的小仓鼠。  小仓鼠的毛是黄色的,所以我就叫它布丁。 布丁小小的,还没有我的小拳头...
表扬就能培养孩子自信? 认可表... 嘉宾  奚林明,中共党员。1984年6月毕业于上海师范大学化学系本科,化学高级教师。最新或2023(...
最新或2023(历届)自己的事...  我有一个我非常喜欢的弹力球。早上,一不小心我把它弄到了洗衣机后面,这下可把我急坏了。我试着把洗衣机...
最新或2023(历届)妈妈去开... 今天一大早,妈妈就去开家长会了。到了中午该吃饭的时候,妈妈还没回来。我有点担心了,老师不会把妈妈单独...
最新或2023(历届)制作心理...  这周末,老师给我们布置了一项特别的任务——制作手抄报!这是一个关于心理健康的手抄报,因为这周是心理...
分布式网关概念及Spring ... 服务网关作为分布式系统对外服务的统一入口,设计功能上具有路由转发、熔断限流、安全认证以...
DETR源码学习(一)之网络模... 这篇文章主要为记录DETR模型的构建过程 首先明确DETR模型的搭建顺序:首先是bac...
最新或2023(历届)可爱的小...  我家养了四头可爱的小金鱼,它们身披金色的鱼鳞,放在一个长方形的鱼缸里,游来游去。  它们看到人站在...