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 Runnable
,new Callable
)是有意义的。这个想法已经存在了一段时间。这里似乎有另一个微妙的使用这个更高效的Actor模式,但在文章中没有明确解释。
我明白使用:
executor.execute(() -> System.out.println(data));
显然效率低(虽然稍微),因为编译器必须创建一个生成的方法invokedynamic
“call site”并在调用时引用它。
这里的优点是(1) direct 方法引用没有invokedynamic
方法生成的开销,(2)还可以允许您将方法参数传递给这个直接参考?在文章中提出的关于我们已经使用和了解的模式的关键点是什么?
答案 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
, 将每个项目包装到一个节点对象中,展示了不相关的临时对象的可能性。使用基于阵列的队列会更加一致,但是,队列不能是非阻塞的。你不能吃蛋糕也吃它...