1. 避免伪共享(false sharing)

1.1 概述

代码层面放的比较近的字段频繁一起并发变更可能导致需要写相同的cache line,写cache line根据MESI协议,要让别的cpu下对应的cache line保持禁写。这导致原本可以从L1 L2cache中获取的数据不得不从L3或者内存中获取,命中率大大降低,性能下降。

参考资料:http://ifeve.com/from-javaeye-false-sharing/

1.2 解决办法

避免伪共享的关键就是避免并发访问的数据在一个cache line。那么解决办法也比较简单了,需要避免伪共享的对象,加个cache line长度的数据,这种方式称为padding。

例如如下保证了long value肯定在一个单独的cache line

public final static class VolatileLong {
    public long pp1, pp2, pp3, pp4, pp5, pp6;
    public volatile long value = 0L;
    public long p1, p2, p3, p4, p5, p6;
} 

另外JDK8中也引入了@Contended注解来支持某个字段单独处理,放到单独的cacheline,不过这个特性也还没正式公开使用,用户自己的类要使用的话需要 -XX:-RestrictContended=false来开启

1.3 考虑cache line的循环遍历

如果手写索引来多层循环遍历,也可以利用cache line来优化性能。
参考示例, 注释部分的循环和下面的交换后性能的差异可以自己比较下。

public class L1CacheMiss {
 private static final int RUNS = 10;
 private static final int DIMENSION_1 = 1024 * 1024;
 private static final int DIMENSION_2 = 62;

private static long[][] longs;

public static void main(String[] args) throws Exception {
 Thread.sleep(10000);
 longs = new long[DIMENSION_1][];
 for (int i = 0; i < DIMENSION_1; i++) {
 longs[i] = new long[DIMENSION_2];
 for (int j = 0; j < DIMENSION_2; j++) {
 longs[i][j] = 0L;
 }
 }
 System.out.println("starting....");

final long start = System.nanoTime();
 long sum = 0L;
 for (int r = 0; r < RUNS; r++) {
     //bad performance
// for (int j = 0; j < DIMENSION_2; j++) {
// for (int i = 0; i < DIMENSION_1; i++) {
// sum += longs[i][j];
// }
// }

//good performance
for (int i = 0; i < DIMENSION_1; i++) {
 for (int j = 0; j < DIMENSION_2; j++) {
 sum += longs[i][j];
 }
 }
 }
 System.out.println("duration = " + (System.nanoTime() - start));
 }
}

jctools

偶然发现的一个并发工具,提供了一些场景化的并发数据结构来针对以下场景:
SPSC - Single Producer Single Consumer (Wait Free, bounded and unbounded)
MPSC - Multi Producer Single Consumer (Lock less, bounded and unbounded)
SPMC - Single Producer Multi Consumer (Lock less, bounded)
MPMC - Multi Producer Multi Consumer (Lock less, bounded)

根据场景化使得锁的粒度控制的更加细,不需要用锁的地方就不用锁。

github地址:https://github.com/JCTools/JCTools
参考资料:netty5笔记-线程模型4-无锁队列MpscLinkedQueue

3. 减少编码和解码开销

待补充。。。

4. 普适技巧

batch、流水线、异步化、无锁数据结构

未完待续