每天一道面试题-CPU伪共享

开发 前端
如果要获取一个内存中的数据,首先会从一级缓存中获取,如果一级缓存中没有,就会从二级缓存中获取,如果二级缓存中没有,就会从三级缓存中获取,如果三级缓存中没有,就会从内存中获取。

前言:

了不起:又到了每天一到面试题的时候了!学弟,最近学习的怎么样啊 

了不起学弟:最近学习的还不错,每天都在学习,每天都在进步! 

了不起:那你最近学习的什么呢? 

了不起学弟:最近在学习CPU伪共享,但是不太理解,能不能给我讲讲呢?

正文:

首先,我们先了解一下CPU的缓存模型。

CPU的缓存分为三层,一级缓存,二级缓存,三级缓存。

如果要获取一个内存中的数据,首先会从一级缓存中获取,如果一级缓存中没有,就会从二级缓存中获取,如果二级缓存中没有,就会从三级缓存中获取,如果三级缓存中没有,就会从内存中获取。

一级缓存是最快的,越到后面就越慢。那CPU的缓存,是由缓存行组成的,每个缓存行的大小是64字节,也就是说,如果我们要获取一个数据,那么就会把这个数据所在的内存地址,以及这个数据所在的内存地址的前后64字节的数据,都会加载到缓存行中。 

聊到这里,我就给大家看看常见的伪共享问题的案例。 

假设有两个线程a和b,同时有两个long类型的变量A和B。两个变量都是互相紧挨着的。那线程a要去操作A,就会把变量A和B一起带入的缓存行,线程b要去操作变量B,也会同时把AB带入缓存行。此时如果线程a把A做了修改,再通过BUS总线进行了通知,内存再做了修改。线程b重新从内存获取变量B,那么此时这种还需要从内存获取变量,这就是伪共享了。 

伪共享:变量AB毫不相关,但是一旦其中一个变量被修改,另一个变量也会被重新加载。

伪共享的解决方案: 

  1. 使用缓存行填充,也就是说,我们在变量AB之间,加入一些无用的变量,让AB不在同一个缓存行中,这样就不会出现伪共享的问题了。

举例:

private static class Padding{
    private volatile long a;
    public volatile long a1,a2,a3,a4,a5,a6,a7;
    private volatile long b;
  }
2.使用@Contened注解在变量上,同时在jdk8中还需要在jvm启动参数中加入
-XX:-RestrictContended,jdk8以上的版本就不需要这个参数即可,
这样就可以解决伪共享的问题了。
private static class Padding{
    @Contended
    private volatile long a;
    @Contended
    private volatile long b;
  }

结尾:

今天就给大家分享了一下关于CPU伪共享的问题,大家如果对CPU缓存模型那块还有疑问,可以多查找一下资料,比如MESI缓存一致模型等等。

责任编辑:武晓燕 来源: Java面试教程
相关推荐

2024-10-11 17:09:27

2011-05-23 11:27:32

面试题面试java

2009-08-11 14:59:57

一道面试题C#算法

2018-03-06 15:30:47

Java面试题

2009-08-11 10:12:07

C#算法

2023-02-04 18:24:10

SeataJava业务

2021-05-31 07:55:44

smartRepeatJavaScript函数

2009-08-11 15:09:44

一道面试题C#算法

2017-11-21 12:15:27

数据库面试题SQL

2022-02-08 18:09:20

JS引擎解析器

2022-04-08 07:52:17

CSS面试题HTML

2021-03-16 05:44:26

JVM面试题运行时数据

2021-10-28 11:40:58

回文链表面试题数据结构

2015-09-02 14:09:19

面试题程序设计

2011-03-02 10:58:16

SQL server入门面试题

2017-09-13 07:15:10

Python读写文件函数

2017-03-10 09:33:16

JavaScript类型

2021-03-27 10:59:45

JavaScript开发代码

2011-06-14 09:12:03

JavaScript

2021-04-13 08:50:21

JS作用域面试题
点赞
收藏

51CTO技术栈公众号