Runnables与方法参考和垃圾

时间:2017-11-22 23:05:00

标签: java multithreading lambda garbage-collection

Java 8中一个相对较新的published article about replacing executors by actors表示使用匿名内部类Runnable,如下所示:

// Functional operation
executor.execute(new Runnable() {
    System.out.println(data);
});

可以理想地用更多垃圾收集器友好技术替换,执行相同的操作:

Actor<String> actor = new Actor<>(parentExecutor, ::onMessage);

// Equivalent functional operation
actor.act("Hello world");

public void onMessage(String message) {
   System.out.println(message);
}

one should generally use method references over anonymous inner classes(即new Runnablenew Callable)是有意义的。这个想法已经存在了一段时间。这里似乎有另一个微妙的使用这个更高效的Actor模式,但在文章中没有明确解释。

我明白使用:

executor.execute(() -> System.out.println(data));

显然效率低(虽然稍微),因为编译器必须创建一个生成的方法invokedynamic“call site”并在调用时引用它。

这里的优点是(1) direct 方法引用没有invokedynamic方法生成的开销,(2)还可以允许您将方法参数传递给这个直接参考?在文章中提出的关于我们已经使用和了解的模式的关键点是什么?

1 个答案:

答案 0 :(得分:1)

文章没有在任何地方说使用lambda表达式而不是方法引用会更糟。

关键的想法是,而不是调用

executor.execute(new Runnable() {
    public void run() {
        System.out.println(data);
    }
});

数百万次,创建数百万Runnable个实例,

Actor<String> actor = new Actor<>(parentExecutor, this::onMessage);

一次并致电

actor.act(data);
数百万次。 Actor在内部使用字符串队列(或您使用的任何数据项),而不是将任何项目包装到另一个对象¹中,并将一个Runnable包装入队列。

执行

时也一样
Actor<String> actor = new Actor<>(parentExecutor, x -> System.out.println(x));

代替甚至

Actor<String> actor = new Actor<>(parentExecutor, new ActorListener<String>() {
    public void onMessage(String message) {
        System.out.println(message);
    }
});

因为这是仅执行一次的代码,因此其技术细节无关紧要。

Lambda表达式或方法引用使得使用此模式更容易,但不是此模式的基石。文章没有另外说明。它所说的只是“随着lambda的使用,它变得非常优雅

¹是挑剔的,它在幕后使用ConcurrentLinkedQueue 将每个项目包装到一个节点对象中,展示了不相关的临时对象的可能性。使用基于阵列的队列会更加一致,但是,队列不能是非阻塞的。你不能吃蛋糕也吃它...