5

我认为这是多线程 Java 应用程序的常见场景,因此我将在此处尝试对其进行描述。

在我的 Java 应用程序中,我有一个threadExecutor对象,它定义了一个包含 5 个线程的池。

ExecutorService threadExecutor = Executors.newFixedThreadPool(5);

sendCallables方法负责将Job列表分配给 Executor。我使用ObjectX
跟踪List。通过这种方式,如果用户想要中断/取消线程,我可以参考未来的列表。像这样的东西:

Map<ObjectX, List<Future<String>>> map = new HashMap<ObjectX, Future<String>>();

public void sendCallables(ObjectX referenceObj, List<Callable<String>> list) {
    ...
    List<Future<String>> futureList = new ArrayList<Future<String>>();
    for(Callable<String> myCallableJob : list) {
        Future<String> future = threadExecutor.submit(myCallableJob);
        futureList.add(future);
    }
    ...
    map.add(referenceObj, futureList);
    ...
}

public void cancelFutures(ObjectX referenceObj) {
    ...
    List<Future<String>> list = map.get(referenceObj);
    for(Future<String> future : list) {
        future.cancel();
    }
    map.remove(referenceObj);
    ....
}

到现在为止还挺好。

现在有些情况下不需要再执行提交的任务了
在这些情况下,取消任务的决定应该由应用程序智能/自动做出。
当用户会话过期或特定流程(与提交的任务相关)在所有作业执行之前结束时,可以在 Web 应用程序中找到此类情况的示例。

所以基本上每次我的应用程序没有意义继续执行作业时,我都需要调用 cancelFutures(referenceObj)。当应用程序需要调用它时,我必须确定每种情况。

我想知道是否有更好的方法来做到这一点。

我正在考虑在WeakHashMap中,一旦应用程序不再引用 referenceObj 就能够清理 Map 但这并不能阻止 Futures 执行,因为我仍然需要在它们上调用 .cancel() (一种与 WeakHashMap remove(Object) 方法关联的 eventHandler ?)

4

2 回答 2

3

我认为您提出的解决方案非常好。如果您真的非常想从referenceObj 中取消垃圾收集,那么您可以结合使用WeakReference 和ReferenceQueue。

在您的执行助手类中声明其中之一。

ReferenceQueue<ObjectX> refQ = new ReferenceQueue<ObjectX>();

每次提交任务批次时执行此操作

new WeakReference<ObjectX>( referenceObj, refQ ).enqueue();

有一个线程只运行这个循环,它会拉出已经变得弱可达(符合 GC 条件)的对象并取消期货/任务。

while (true)
{
    // this blocks
    ObjectX referenceObj = refQ.remove().get();
    cancelFutures( referenceObj );
}
于 2010-03-26T14:52:24.157 回答
0

如果我正确理解您的问题,那么您会发生各种类型的活动,并且您不想仅仅因为它们可以被取消而将这些活动捆绑在一起。

在我看来,每个需要取消的案例都应该触发一个事件。事件监听器会监听这些事件并取消相关Future的。

您关于会话的示例 - 您将有一个实现javax.servlet.http.HttpSessionListner、检测需要取消的相关任务并触发事件以取消这些任务的类。由于一切都是异步的,因此您不会关心取消的任务是否完成,因此不会丢失任何内容。

于 2010-03-26T14:42:21.440 回答