上一回说到FastThreadLocal中存在一个缓存行的事,这回咱们来聊聊一个问题。
问题的引出现在有一个任务,FBI要求你去追踪一辆小汽车,你收集到数据后,你该怎么反馈给boss?你怎么把这个过程展示出来。
其实就是一段代码的事。
public static void main(String[] args) {
Point point = new Point();
new Thread(() -> {
int i = 0;
while (i++ < 10_0000) {
point.x = 1;//x数据的更新
}
}).start();
new Thread(() -> {
int i = 0;
while (i++ < 10_0000) {
point.y = 2;//y数据的更新
}
}).start();
}
public static class Point {
public int x = 0;
public int y = 0;
}
用一个类来表示点(汽车),它最初是在原点(0,0),一个线程更新X坐标的值,一个线程更新Y坐标的值。这样就表示出汽车的轨迹,并可以动态展示。OK,你的任务完成了。但是作为程序员,想一想有没有什么问题。
理论上是没有什么问题的,但理论上它也是有问题的。当你让你同时监视上亿的车辆,你这程序会快吗?能实时同步吗?
在CPU和内存条之间存在着高速缓存,就是L1、L2、L3级缓存,越靠近CPU的缓存越快,容量
也越小。而L1、L2是核独有的,L3是共有的。这样当两个核共用一个缓存时,就需要同步,以保持一致性。当数据量上去后,这个同步的耗时就体现出来了。
拿隔壁的一张图来展示。
当x、y在一块内存的时候,假如线程1只修改x,线程2只修改y,这个时候core1修改x,就必须同步,core2亦复如是,而事实让他们是毫无影响的。
这个时候你可能会想到,把他们放入不同的内存块中,core1读一个,core2读另一个。没错,这就是我们的解决办法。
CPU每次从主存中读取数据的时候,它每次读取的那一块内存是多大呢?64byte。它有一个专有名词:缓存行。
那对于FastThreadLocal这个对象来说,它就是进行了无效数据的填充。
public long rp1, rp2, rp3, rp4, rp5, rp6, rp7, rp8, rp9;
所以,无用也有大用。



