在调用EJB方法时中断客户端线程的正确方法是什么?

时间:2011-03-08 10:37:21

标签: java multithreading ejb interrupted-exception

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

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

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

这个结构正在使用之前的服务器连接器,因为我是唯一一个检查进程中断标志的人。我的问题是我现在在客户端使用EJB方法调用,并且他们对中断的线程反应很差。在EJB调用期间中断线程将触发RuntimeException,其中包含InterruptedException。这似乎不太正常。

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

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

3 个答案:

答案 0 :(得分:1)

看到你不介意在服务器上继续使用过时的EJB调用,为什么不允许调用线程“自然地”终止但是丢弃结果因为它的调用已经被另一个线程取代了?我没有时间提供示例实现,但您可能会发现使用Future和相关的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;
    }

}

这可能会崩溃并烧毁,但希望它能指出你的一条询问线......

答案 1 :(得分:0)

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

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

在任何情况下,要正确地执行此操作,您需要您希望停止处理这两种情况的线程运行的代码。这里没有银弹。

答案 2 :(得分: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;
}

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

在理想世界中,我们应该选择one of the solutions给出的Rich