3

Google Guavaでキャッシュを構築しようとしていますが、期限切れのオブジェクトに対して計算を実行したいと思います。一部のオブジェクトが削除された場合、removalListenerは通知します。

メインアプリケーションとは別のスレッドでremovalListenerを実行したり、期限切れのオブジェクト(以下の簡単な例では整数3)を計算を処理する別のスレッドに渡すにはどうすればよいですか?

編集:計算はかなり短いですが、頻繁に発生するため、毎回新しいスレッドを作成するのではなく(数千のスレッドになります)、すべてのオブジェクトを計算する1人(または2人)がいます。

簡単な例:

Cache<String, Integer> cache = CacheBuilder.newBuilder().maximumSize(100)
        .expireAfterAccess(100, TimeUnit.NANOSECONDS)
        .removalListener(new RemovalListener<String, Integer>() {
            public void onRemoval(final RemovalNotification notification) {
                if (notification.getCause() == RemovalCause.EXPIRED) {
                    System.out.println("removed " + notification.getValue());
                    // do calculation=> this should be in another thread
                }
            }
        })
        .build();
 cache.put("test1", 3);
 cache.cleanUp();
4

5 に答える 5

9

エグゼキュータでリスナーを実行するには、RemovalListeners.asynchronousでリスナーをラップします。

.removalListener(非同期(新しいRemovalListener(){...}、エグゼキュータ))

于 2012-07-27T14:37:00.893 に答える
7

Executorsファクトリメソッドの1つを使用してExecutorServiceを作成し、必要なたびに新しいRunnableをこのexecutorに送信します。

private ExecutorService executor = Executors.newSingleThreadExecutor();

...

public void onRemoval(final RemovalNotification notification) {
    if (notification.getCause() == RemovalCause.EXPIRED) {
        System.out.println("removed " + notification.getValue());
        submitCalculation(notification.getValue());
    }
}

private void submitCalculation(final Integer value) {
    Runnable task = new Runnable() {
        @Override
        public void run() {
            // call your calculation here
        }
    };
    executor.submit(task);
}
于 2012-07-27T14:06:04.563 に答える
3

新しいクラスを作成し、そのjava.utils.Runnableようにインターフェースを実装できます。

public class MyWorkerThread implements Runnable {

    public MyWorkerThread(/*params*/) {
        //set your instance variables here
        //then start the thread
        (new Thread(this)).start();
    }

    public void run() {
        //do useful things
    }
}

コンストラクターを呼び出してnewを作成するMyWorkerThreadと、コンストラクターが終了するとすぐに実行が呼び出し元のコードに戻され、run()メソッド内でコードを実行する別のスレッドが開始されます。

MyWorkerThreadオブジェクトをすぐに開始せずに作成したい場合はThread.start()、コンストラクターからコードを削除し、後でインスタンスから手動でスレッドを呼び出すことができます。

MyWorkerThread t = new MyWorkerThread();
//later
(new Thread(t)).start();

または、Threadオブジェクトへの参照を保持して、割り込み結合などのグルーヴィーなことを実行できるようにする場合は、そのようにします。

Thread myThread = new Thread(t);
myThread.start();
//some other time
myThread.interrupt();
于 2012-07-27T14:03:50.280 に答える
1

期限切れのエンティティの中間キューを作成するだけです(期限切れリスナーはこのキューに期限切れのオブジェクトを追加するだけです)-たとえば、ある種のブロッキングメモリ内キュー-ArrayBlockingQueue、LinkedBlockingDeque。

次に、poll()メソッドを使用してオブジェクトを消費するスレッドプールとハンドラー(サイズを構成可能)を設定できます。

高性能キューの場合-必要に応じて、より高度な非ブロッキングキューの実装についてアドバイスできます。また、ここで高性能の非ブロッキングキューについて詳しく読むことができます。最初の要素をConcurrentLinkedQueueにアトミックに追加します

于 2012-07-27T14:04:20.227 に答える
1

エグゼキュータサービスを使用して、タスクを別のスレッドにディスパッチします。ExecutorServiceには、プロデューサースレッドとコンシューマースレッド間の参照を安全に公開するために使用される内部ブロッキングキューがあります。ファクトリクラスのエグゼキュータExecutorServiceを使用して、さまざまなスレッド管理戦略でさまざまな ものを作成できます。

private ExecutorService cleanupExecutor = Executors.newFixedThreadPool(CLEANUP_THREADPOOL_SIZE); 
...
public void onRemoval(final RemovalNotification notification) {
    if (notification.getCause() == RemovalCause.EXPIRED) {
        System.out.println("removed " + notification.getValue());
        doAsyncCalculation(notification.getValue());
    }
}

private void doAsyncCalculation(final Object obj) {
    cleanupExecutor.submit(new Runnable() {
        public void run() {
            expensiveOperation(obj);
        }
    }
}

doAsyncCalculation実行する新しいタスクを作成していますが、新しいスレッドは作成していません。executorサービスは、executorServiceに関連付けられたスレッドプール内のスレッドへのタスクのディスパッチを処理します。

于 2012-07-27T14:42:21.787 に答える