一郎科技|Java多线程_缓存对齐( 二 )


我们设计一个实验去验证缓存行对齐的导致的性能问题 , 及相关的解决后的效率问题 。 具体代码见第三小节 。 这里的思路是 , 首先 , 我们写一个类T , 这个类里面有一个用volatile修饰的long属性的值 , 这个值占用8个字节 。 然后声明一个静态数组 , 包含两个元素 , 分别T的两个对象 。 然后开启两个线程 , 让两个线程分别给数组的第一个值和第二个值赋值 , 执行一百万次 , 看执行的耗时 。
这个时候 , 代码执行的时候如1.2的图中所示 , 假设数组中第一个值为X , 第二个值为Y 。 左侧框内为第一个线程 , 执行修改X值的操作 , 右侧框内为第二个线程 , 修改Y的值 。 因为两个值在同一个缓存行中 , 所以在X值在读取的时候 , 同时将X值和Y值一起读入缓存 。 第二个线程只修改Y的值 , 但是同样将XY全部读入缓存 。 线程1中X值发生修改后 , 第二个线程中的X值需要进行更新 。 而线程2修改Y的值后也需要同样的操作 , 但是这个更新不是必要的 , 而且会影响执行的效率 。
解决方法是:我们给第T的long值之前加入8个long值 , 这样Y值就会被挤到其他缓存行 , 这样彼此修改的时候就不会产生干扰 , 提高代码执行效率 。
下面是具体验证的代码 , 其中在没有加入父类的时候 , 是相互干扰时的执行耗时 。 第二个是加入父类后 , 不再干扰时的耗时 , 执行后可以看出 , 第二套代码在执行的时候 , 代码要优于第一套代码的执行 。
3.缓存对齐的代码实现 1 public class T01_CacheLinePadding { 2private static class T{ 3public volatile long x = 0L; 4} 5public static T[] orr = new T[2]; 6static { 7orr[0]= new T(); 8orr[1]= new T(); 9}10public static void main(String[] args) throws Exception {11Thread t1 = new Thread(()->{12for (long i = 0; i < 1000_000L; i++) {13orr[0].x = i;14}15});16Thread t2 = new Thread(()->{17for (long i = 0; i < 1000_000L; i++) {18orr[1].x = i;19}20});21final long start = System.nanoTime();22t1.start();23t2.start();24t1.join();25t2.join();26System.out.println((System.nanoTime()-start)/100_000);27}28 } 1 package msb; 2 /** 3* 缓存行对齐问题代码 4* @author L Ys 5* 6*/ 7 public class T02_CacheLinePadding { 8private static class Padding{ 9public volatile long p1,p2,p3,p4,p5,p6,p7;10}11private static class T extends Padding{12public volatile long x = 0L;13}14public static T[] orr = new T[2];15static {16orr[0]= new T();17orr[1]= new T();18}19public static void main(String[] args) throws Exception {20Thread t1 = new Thread(()->{21for (long i = 0; i < 1000_000L; i++) {22orr[0].x = i;23}24});25Thread t2 = new Thread(()->{26for (long i = 0; i < 1000_000L; i++) {27orr[1].x = i;28}29});30final long start = System.nanoTime();31t1.start();32t2.start();33t1.join();34t2.join();35System.out.println((System.nanoTime()-start)/100_000);36}37 }作者:精品唯居原文地址:


推荐阅读