2017-11-22 10 views
1

は、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「コール・サイト」を作成し、呼び出されたときにそれを参照するために:

は、私が使用していることを理解しています。

は、(1)直接メソッド参照がinvokedynamicメソッド生成のオーバーヘッドを持っていないと(2)ができることをここでの利点です加えて、あなたは、この直接参照するメソッドのパラメータを渡すことができますか?記事で紹介したこのアイデアを、すでに使用していて知っているパターンよりも重要なものにしているのは何ですか?

+1

最初にリンクされた記事は間違っています。各メソッド参照のオブジェクトを作成しなければならないので、GCに優しいわけではありません。これは、匿名クラスオブジェクトを異なるタイプのオブジェクトに置き換えたばかりです。メソッド参照またはラムダは新しいクラスを作成せず、それは2番目のリンクのポイントですが、改善されたGCの最初のリンクのポイントは間違っているため、クラスが残っていない方が良いです。あなたがウェブ上で見つけたものすべてを信じてはいけません。 – Andreas

+0

@アンドレアスあなたが言っていることが真実ならば、私は驚いています。それ以上のGCの親切ではないこと。私は、Clebert Suconic - 記事の著者であり、新しいActiveMQに関するApacheの一次コミッター - おそらくそのことを述べる前に宿題をしていたというメリットについて語っています。 – Dovmo

+0

@Andreas匿名クラスは囲むオブジェクトをキャプチャし、ラムダまたはメソッドリファレンスは必要なものだけをキャプチャします。たぶんそれはもっとGCに優しいという意味ですか? – maaartinus

答えて

1

この記事では、メソッドリファレンスの代わりにラムダ式を使用すると悪化するとは言いません。

キーアイデアは、代わりにRunnableインスタンスの数百万人を作成し、時代の

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

百万人を呼んで、あなたは

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

一度やると

actor.act(data); 

を呼び出すことです何百万回も。 Actorは、内部的に文字列(または使用するデータ項目)のキューを使用し、アイテムを別のオブジェクトにラッピングせずに、そして単一のRunnableをエンキューします。その技術的な詳細は無関係であるので、代わりに、またはそれとさえ

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

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

を行っているときに、同じようにうまくいくでしょう

は、一度だけ実行されるコードです。

ラムダ式またはメソッド参照は、このパターンを使用しやすくしますが、このパターンの基礎ではありません。そして、その記事は別のことを言っていない。それが言うすべてが


¹がつべこべするために「それはが本当にエレガント取得ラムダの使用に」で、それは実証し、は、ノードオブジェクトに各項目をラップしない舞台裏ConcurrentLinkedQueueを、使用していますどのように無関係な一時的なオブジェクトがあるかもしれません。配列ベースのキューを使用する方がより一貫性がありますが、キューを非ブロックにすることはできません。あなたはケーキを食べて食べることはできません...

+0

OK、私はコードをもう一度見ていると言っています。私が文章でそれを要約することができれば;それは基本的に単なる "アクター"を作成し、その抽象化を通して同期を管理するという構文的な砂糖を備えた、GCに優しいプロデューサー - 消費者パターン実装です。私はこの考えが好きです。ありがとうございました!私は他の人がこれで恩恵を受けることを望む – Dovmo

関連する問題