美团三面面经,底层知识总结,阿里牛逼

走得越远,运算耗费的时间就越长。

所以如果进行一些很频繁的运算,要确保数据在 L1 缓存中。

按块读取

读取数据时,由于局部性原理,将相邻的数据一块读取。可以提高效率。(不管是硬盘往内存读或者内存往缓存读)

缓存行Cache Line:

每个缓存里面都是由缓存行组成的,缓存系统中是以**缓存行(cache line)**为单位存储的。缓存行是2的整数幂个连续字节,一般为32-256个字节。

缓存行越大,局部性空间效率越高,但读取时间慢

缓存行越小,局部性空间效率越低,但读取时间快

取一个折中值,最常见的缓存行大小是64个字节

多个CPU时,需要保持数据的一致性,这里用的是一致性协议

MESI Cache一致性协议

伪共享:

当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能,这就是伪共享。

在程序运行的过程中,缓存每次更新都从主内存中加载连续的 64 个字节。因此,如果访问一个 long 类型的数组时,当数组中的一个值被加载到缓存中时,另外 7 个元素也会被加载到缓存中。

但是,如果使用的数据结构中的项在内存中不是彼此相邻的,比如链表,那么将得不到免费缓存加载带来的好处。

不过,这种免费加载也有一个坏处。设想如果我们有个 long 类型的变量 a,它不是数组的一部分,而是一个单独的变量,并且还有另外一个 long 类型的变量 b 紧挨着它,那么当加载 a 的时候将免费加载 b。

看起来似乎没有什么毛病,但是如果一个 CPU 核心的线程在对 a 进行修改,另一个 CPU 核心的线程却在对 b 进行读取。

当前者修改 a 时,会把 a 和 b 同时加载到前者核心的缓存行中,更新完 a 后其它所有包含 a 的缓存行都将失效,因为其它缓存中的 a 不是最新值了。

而当后者读取 b 时,发现这个缓存行已经失效了,需要从主内存中重新加载。

请记住,我们的缓存都是以缓存行作为一个单位来处理的,所以失效 a 的缓存的同时,也会把 b 失效,反之亦然。

伪共享例子:

package c_020;

public class FalseSharing {

public static void main(String[] args) throws InterruptedException {

testPointer(new Pointer());

}

private static void testPointer(Pointer pointer) throws InterruptedException {

long start = System.currentTimeMillis();

Thread t1 = new Thread(() -> {

for (int i = 0; i < 100000000; i++) {

pointer.x++;

}

});

Thread t2 = new Thread(() -> {

for (int i = 0; i < 100000000; i++) {

pointer.y++;

}

});

t1.start();

t2.start();

t1.join();

t2.join();

System.out.println(System.currentTimeMillis() - start);

System.out.println(pointer);

}

}

class Pointer {

volatile long x;

volatile long y;

}

这个例子中,我们声明了一个 Pointer 的类,它包含 x 和 y 两个变量(必须声明为volatile,保证可见性,关于内存屏障的东西我们后面再讲),一个线程对 x 进行自增1亿次,一个线程对 y 进行自增1亿次。

可以看到,x 和 y 完全没有任何关系,但是更新 x 的时候会把其它包含 x 的缓存行失效,同时也就失效了 y,运行这段程序输出的时间为3258ms

避免伪共享


伪共享的原理我们知道了,一个缓存行是 64 个字节,一个 long 类型是 8 个字节,所以避免伪共享也很简单,大概有以下三种方式:

(1)在两个 long 类型的变量之间再加 7 个 long 类型

package c_020;

public class FalseSharing2 {

public static void main(String[] args) throws InterruptedException {

testPointer(new Pointer2());

}

private static void testPointer(Pointer2 pointer) throws InterruptedException {

long start = System.currentTimeMillis();

Thread t1 = new Thread(() -> {

for (int i = 0; i < 100000000; i++) {

pointer.x++;

}

});

Thread t2 = new Thread(() -> {

for (int i = 0; i < 100000000; i++) {

pointer.y++;

}

});

t1.start();

t2.start();

t1.join();

t2.join();

System.out.println(System.currentTimeMillis() - start);

System.out.println(pointer);

}

}

class Pointer2 {

volatile long x;

long p1, p2, p3, p4, p5, p6, p7;

volatile long y;

}

再次运行程序,会发现输出时间神奇的缩短为了499ms

(2)重新创建自己的 long 类型,而不是 java 自带的 long

class Pointer {

MyLong x = new MyLong();

MyLong y = new MyLong();

}

class MyLong {

volatile long value;

long p1, p2, p3, p4, p5, p6, p7;

}

这种个人感觉和第一种一样,就不演示了

(3)使用 @sun.misc.Contended 注解(java8)

修改 MyLong 如下:

@sun.misc.Contended

class MyLong {

volatile long value;

}

package c_020;

public class FalseSharing3 {

public static void main(String[] args) throws InterruptedException {

testPointer(new Point3());

}

private static void testPointer(Point3 pointer) throws InterruptedException {

long start = System.currentTimeMillis();

Thread t1 = new Thread(() -> {

for (int i = 0; i < 100000000; i++) {

pointer.x.value++;

}

});

Thread t2 = new Thread(() -> {

for (int i = 0; i < 100000000; i++) {

pointer.y.value++;

}

});

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

写在最后

还有一份JAVA核心知识点整理(PDF):JVM,JAVA集合,JAVA多线程并发,JAVA基础,Spring原理,微服务,Netty与RPC,网络,日志,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算…

image

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

式缓存**,Hadoop,Spark,Storm,YARN,机器学习,云计算…

[外链图片转存中…(img-2k8mj1jD-1712531937877)]

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值