28

スレッドがイベントを 2 番目のスレッドの着信キューにプッシュするという古典的な問題があります。今回だけは、パフォーマンスにとても興味があります。私が達成したいことは次のとおりです。

  • キュー、プロデューサーのプッシュ、レシーバーのポップへの同時アクセスが必要です。
  • キューが空の場合、コンシューマーがプロデューサーを待ってキューにブロックするようにします。

最初のアイデアは a を使用することでしたがLinkedBlockingQueue、すぐにそれが同時実行ではなく、パフォーマンスが低下することに気付きました。一方、私は現在 a を使用していますConcurrentLinkedQueueが、それでも各出版物にwait()/のコストを支払っています。notify()コンシューマーは、空のキューを見つけてもブロックしないため、同期wait()してロックする必要があります。一方、プロデューサーは、notify()すべてのパブリケーションでそのロックを取得する必要があります。sycnhronized (lock) {lock.notify()}全体的な結果として、必要がない場合でも、すべての出版物のコストを私が支払って います。

ここで必要だと思うのは、ブロックと並行の両方のキューです。プッシュされた要素がリストの最初にある場合、オブジェクトに余分なものを付けて、のpush()ように機能する操作を想像します。プッシュには次の要素との接続が必要なため、このようなチェックは既に に存在すると考えています。したがって、これは外部ロックで毎回同期するよりもはるかに高速です。ConcurrentLinkedQueuenotify()ConcurrentLinkedQueue

このようなものは利用可能/合理的ですか?

4

6 に答える 6

12

java.util.concurrent.LinkedBlockingQueue疑問を持たずに続けられると思います。並行です。ただし、そのパフォーマンスについてはわかりません。おそらく、他の実装のBlockingQueue方が適しているでしょう。数は多くありませんので、性能テストを行って測定してください。

于 2009-07-31T13:12:10.347 に答える
6

この回答https://stackoverflow.com/a/1212515/1102730に似ていますが、少し異なります..私はExecutorService. を使用してインスタンス化できますExecutors.newSingleThreadExecutor()。BufferedImages をファイルに読み書きするための同時キューと、読み書きの原子性が必要でした。ファイル IO はソースのネット IO より桁違いに高速であるため、必要なのは単一のスレッドだけです。また、私はパフォーマンスよりもアクションの原子性と正確性に関心がありましたが、このアプローチはプール内の複数のスレッドで実行して速度を上げることもできます。

画像を取得するには (Try-Catch-Finally を省略):

Future<BufferedImage> futureImage = executorService.submit(new Callable<BufferedImage>() {
    @Override
        public BufferedImage call() throws Exception {
            ImageInputStream is = new FileImageInputStream(file);
            return  ImageIO.read(is);
        }
    })

image = futureImage.get();

画像を保存するには (Try-Catch-Finally を省略):

Future<Boolean> futureWrite = executorService.submit(new Callable<Boolean>() {
    @Override
    public Boolean call() {
        FileOutputStream os = new FileOutputStream(file); 
        return ImageIO.write(image, getFileFormat(), os);  
    }
});

boolean wasWritten = futureWrite.get();

最終ブロックでストリームをフラッシュして閉じる必要があることに注意することが重要です。他のソリューションと比較してどのように機能するかはわかりませんが、非常に用途が広いです。

于 2012-08-27T20:09:51.093 に答える
5

ThreadPoolExecutor newSingleThreadExecutorをご覧になることをお勧めします。タスクの順序を維持し、Callablesをエグゼキュータに送信すると、探しているブロッキング動作も取得できます。

于 2009-07-31T13:23:01.463 に答える
4

jsr166 から LinkedTransferQueue を試すことができます: http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166y/

これは要件を満たし、オファー/ポーリング操作のオーバーヘッドが少なくなります。コードからわかるように、キューが空でない場合、要素のポーリングにアトミック操作が使用されます。キューが空になると、しばらくの間スピンし、失敗した場合はスレッドを保留します。あなたの場合に役立つと思います。

于 2009-08-01T06:48:12.060 に答える
3

あるスレッドから別のスレッドにデータを渡す必要があるときはいつでも、ArrayBlockingQueue を使用します。put メソッドと take メソッドを使用します (フル/空の場合はブロックされます)。

于 2009-07-31T17:12:22.870 に答える
2

を実装しているクラスBlockingQueueの一覧です。

チェックアウトすることをお勧めしSynchronousQueueます。

@Rorick がコメントで述べたように、これらの実装はすべて並行していると思います。あなたの懸念は場違いLinkedBlockingQueueかもしれないと思います。

于 2009-07-31T13:00:56.250 に答える