关于lambdas和并发的意外结果

时间:2016-11-05 00:19:29

标签: java lambda concurrency

我一直在研究SomeComponent.propTypes = { obj: React.PropTypes.shape({ id: PropTypes.number, name: PropTypes.name }) }; 关键字,以及如何使用它来操纵内存从CPU缓存中存储和访问的方式。我正在使用一个简单的测试程序来探索如何在不同的缓存行上存储2个变量(每个变量由并发执行的线程访问),从而提高读/写速度。显然,这种方法永远不会在现实世界中使用,但是,我发现以下程序在演示和理解数据如何存储在CPU缓存中非常有用,尽管非常粗略:

volatile

}

这里,代码填充public class Volatile { private volatile int a = 0; private long dummy1 = 0; private long dummy2 = 0; private long dummy3 = 0; private long dummy4 = 0; private volatile int b = 0; private static long lastA; private static long lastB; public static void main(String[] args) { final Volatile instance = new Volatile(); new Thread(new Runnable(){ @Override public void run() { lastA = System.nanoTime(); while(true){ instance.a++; if(instance.a % 100_000_000 == 0){ System.out.println("A: " + (System.nanoTime() - lastA) / 1000000 + "ms"); lastA = System.nanoTime(); instance.a = 0; } } } }).start(); new Thread(new Runnable(){ @Override public void run() { lastB = System.nanoTime(); while(true){ instance.b++; if(instance.b % 100_000_000 == 0){ System.out.println("B: " + (System.nanoTime() - lastB) / 1000000 + "ms"); lastB = System.nanoTime(); instance.b = 0; } } } }).start(); } a之间的虚拟变量,这样它们将存储在不同的缓存行中,访问它们的2个线程不会发生冲突。该程序产生的结果与预期一致,我的CPU将每个变量递增到b的时间大约为600-700 ms。删除虚拟变量会将此时间增加到大约3000-4000 ms。

这是我遇到一些我不理解的行为的地方。

我将代码完全复制到一个单独的类中,但是,我用lambda表达式替换了传递给线程创建的匿名内部类:

100_000_000

final VolatileLambda instance = new VolatileLambda();
        new Thread(() -> {
                lastA = System.nanoTime();
                while(true){

当我使用lambdas运行第二个程序时,我遇到了与第一个程序不同的结果,因为填充变量不再足以将 new Thread(() -> { lastB = System.nanoTime(); while(true){ a分隔到单独的缓存行上,导致线程冲突并再次产生3000-4000毫秒的输出。这是通过在伪longs之后声明一个额外的单个虚拟字节变量来解决的:

b

声明这个额外字节后的输出再次大约为600-700毫秒。

我在不同系统上多次复制这种比较,奇怪的是,这并没有产生一致的结果。有时,在匿名内部类上使用lambdas对输出没有影响,有时它会。即使在不同时间在同一系统上进行相同的比较也不总能产生相同的结果。

我在试图解释这种行为时感到茫然,并且非常感谢任何帮助。随意请求澄清任何事情,因为我可能没有很好地解释这一点。

谢谢!

0 个答案:

没有答案