私はCallable
オブジェクトをに送信していますがThreadPoolExecutor
、それらはメモリに残っているようです。
Eclipse用のMATツールでヒープダンプを見ると、Callable
オブジェクトがFutureTask$Sync
の呼び出し可能な変数によって参照されていることがわかります。これは、の同期変数FutureTask$Sync
によって参照されます。これは、のthis$0変数によって参照されます。FutureTask
FutureTask
FutureTask$Sync
私はこれについて読んだことがあり(ここ、ここ、そしてSOで) 、呼び出し可能オブジェクトが's submit()FutureTask
にラップされThreadPoolExecutor
、呼び出し可能オブジェクトへの参照を永久に保持しているようです。
私が混乱しているのは、FutureTask
ガベージコレクションを確実に取得して、呼び出し可能オブジェクトをメモリに保持し続けないようにし、呼び出し可能オブジェクトがメモリに保持している可能性のあるものを保持する方法です。
私の特定の状況について詳しく説明するためにThreadPoolExecutor
、必要に応じて送信されたすべてのタスクをキャンセルできるように実装しようとしています。私はSOや他の場所で見つけたいくつかの異なる方法を試しました。たとえば、エグゼキュータを完全にシャットダウンし(などで)、先物のリストを保持し、それらすべてに対してキャンセルを呼び出してから、shutdown()
先物のリストをクリアします。理想的には、シャットダウンする必要はなく、必要に応じてクリアする必要があります。shutdownNow()
submit()
cancel()
これらの方法のすべてが違いを生むわけではないようです。呼び出し可能オブジェクトをプールに送信すると、それが固執してしまう可能性が高くなります。
私は何が間違っているのですか?
ありがとう。
編集:
要求に応じて、これがThreadPoolExecutorのコンストラクターです。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
さらにテストした後、ThreadPoolExecutorに送信されたタスクを終了させても、リークがないことがわかります。とにかくそれらをキャンセルしようとすると:
shutdownNow()
または、将来への参照を保存し、後でキャンセルを呼び出す:
Future referenceToCancelLater = submit(task);
...
referenceToCancelLater.cancel(false);
または、次のような方法でキューから削除します。
getQueue.drainTo(someList)
また
getQueue.clear()
または先物への保存された参照をループして呼び出します:
getQueue.remove(task)
これらのケースのいずれかにより、FutureTaskは上記のように固執します。
したがって、これらすべての本当の問題は、FutureTaskがガベージコレクションされ、永久にリークされないように、ThreadPoolExecutorからアイテムを適切にキャンセルまたは削除する方法です。