1

我有一个 Java 客户端,它在新线程中管理其服务器调用,以防止 GUI 冻结。

即使在许多地方都阻止了这种情况,也有可能在同一模型上再次调用该方法,例如使用不同的参数。在这种情况下,我显然希望具有最新参数的最新调用成为“成功”并显示其结果的调用。

我有一个系统跟踪先前启动的线程,并在启动新线程之前中断它(Thread.interrupt())。if (Thread.currentThread().isInterrupted()然后,其他方法在将新结果发送到 GUI 元素之前检查它们是否在非中断线程中运行(使用)。

这个结构与以前的服务器连接器一起工作,因为我是唯一一个检查进程中断标志的人。我的问题是我现在在客户端中使用 EJB 方法调用,它们对中断的线程反应很差。在 EJB 调用期间中断线程将触发RuntimeException包含InterruptedException. 而且这似乎不是一件正常的事情。

显然,我可以在每个服务器调用中捕获 RuntimeExceptions 并检查它们的中断原因,但它似乎不是很“干净”。

我的问题是:在这种情况下我能做什么?中断运行 EJB 方法调用的线程的正确方法是什么?

4

3 回答 3

1

既然您不介意在服务器上继续过时的 EJB 调用,为什么不让调用线程“自然地”终止,而是丢弃结果,因为它的调用已被另一个线程取代?我没有时间提供示例实现,但您可能会发现您对Futures 和相关的 Java 并发类有所了解。

编辑

除此之外,您可能会发现类似这样的方法可以解决问题,但对我来说感觉很老套,我相信还有更优雅的解决方案。

在调用线程上(可能是按钮的 onclick 方法):

AsynchronousResultManager.registerRequest("UNIQUE_IDENTIFIER", runnableExecuteRequest);

registerRequest会做类似的事情:

registerClick(String id, Runnable execution) {
    AtomicReference ref = executions.get(id); //executions is a Map<String, AtomicReference> created as a a computing map by Guava MapMaker
    execution.setReference(ref); //so that the Runnable has a reference to it later
    ref.set(execution); //this will overwrite an existing reference to a previous invocation.
    //here you need to actually kick off your thread in whatever way works best for you
}

执行请求的runnable将是以下的子类:

public abstract class RequestRunnable implements Runnable {

    private AtomicReference ref;

    public void run() {
        doRunInternal(); //actually go off and do the request to the J2EE server
        if (this == ref.get()) { //ie if the current runnable is the same as in the reference, we can proceed to actually dispatch the result
            dispatchResult(); //this method would do something like add a runnable to the SwingWorkerThread
        }
    }

    protected abstract void doRunInternal();
    protected abstract void dispatchResult();

    public void setReference(AtomicReference ref) {
        this.ref = ref;
    }

}

这可能会崩溃并烧毁,但希望它可以为您指明一条询问线……

于 2011-03-08T11:31:31.153 回答
0

要停止线程,您需要执行 2 种操作:

  • 如果线程正在等待阻塞操作(IO、网络、锁...),您需要中断它。将抛出一个 InterruptedException,使正在运行的代码有机会捕获异常并以适当的方式停止。
  • 如果线程只是在做一些处理, Thread.interrupt() 将无济于事。不会抛出异常,线程将继续处理它。处理代码需要定期检查您是否仍希望进程继续。

无论如何,要正确执行此操作,您需要由要停止的线程运行的代码处理这两种情况。这里没有灵丹妙药。

于 2011-03-08T10:54:45.567 回答
0

鉴于现有架构,我最终从每个服务器调用中捕获 RuntimeException,形式如下:

try {
    return getEJBService().getServiceResult(param, param, param);
} catch (RuntimeException e) {
    Throwable cause = e.getCause();
    if (cause instanceof InterruptedException)
        throw (InterruptedException)cause;
    else
        throw e;
}

它不是很漂亮,但至少它允许我根据当前模型的中断采取行动。

在理想的世界中,人们宁愿选择Rich给出的解决方案之一

于 2011-03-14T09:52:01.880 回答