Как правильно прервать поток клиента во время вызова метода EJB? - PullRequest
1 голос
/ 08 марта 2011

У меня есть Java-клиент, который управляет вызовами своего сервера в новых потоках, чтобы предотвратить зависание графического интерфейса.

Даже если это запрещено во многих местах, возможно, что метод будет вызван снова на той же модели, например, с другими параметрами. В таком случае я, очевидно, хочу, чтобы новейший вызов с самыми последними параметрами был «успешным» и отображал его результаты.

У меня есть система, которая отслеживает ранее запущенный поток и прерывает его перед запуском нового (Thread.interrupt()). Затем другие методы проверяют, работают ли они в непрерывном потоке (используя if (Thread.currentThread().isInterrupted()), прежде чем запускать новые результаты для элементов графического интерфейса.

Эта структура работала с предыдущим соединителем к серверу, так как я был единственным, кто проверял флаг прерывания в процессе. Моя проблема в том, что я сейчас использую вызовы методов EJB в клиенте, и они плохо реагируют на прерванный поток. Прерывание потока во время вызова EJB вызовет RuntimeException, включая InterruptedException. И это не похоже на нормальное явление.

Очевидно, что я мог бы перехватывать исключения RuntimeException при каждом вызове сервера и проверять их причину прерывания, но это не кажется "чистым".

Мой вопрос: что я могу сделать в таком контексте? Как правильно прервать поток, выполняющий вызов метода EJB?

Ответы [ 3 ]

1 голос
/ 08 марта 2011

Учитывая, что вы не возражаете против устаревшего вызова EJB, продолжающегося на сервере, почему бы не позволить вызывающему потоку завершить «естественным образом», но отказаться от результата, потому что его вызов был заменен другим потоком?У меня нет времени, чтобы предоставить пример реализации, но вы можете обнаружить, что вы получаете некоторый пробег с Future s и связанными классами параллелизма Java.

Edit

В дополнение к этому, вы можете найти что-то вроде этого, но это кажется мне счастливым, и я уверен, что есть более элегантные решения.

В вызывающем потоке (возможно, метод 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;
    }

}

Это, вероятно, приведет к сбою и сгоранию, но, надеюсь, оно укажет вам направление расследования ...

0 голосов
/ 14 марта 2011

Учитывая существующую архитектуру, я, наконец, пошел с перехватом 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 .

0 голосов
/ 08 марта 2011

Чтобы остановить поток, вам необходимо выполнить 2 действия:

  • , если поток ожидает операции блокировки (IO, сеть, блокировка ...), вам необходимо прервать его.Будет сгенерировано исключение InterruptedException, дающее работающему коду возможность перехватить исключение и правильно его остановить.
  • Если поток просто выполняет некоторую обработку, Thread.interrupt () не поможет.Не будет выдано никаких исключений, и поток просто продолжит свою обработку.Код обработки должен регулярно проверять, что вы все еще хотите, чтобы процесс продолжался.

В любом случае, чтобы сделать это правильно, вам нужно, чтобы код, выполняемый вашим потоком,Вы хотите прекратить разбираться с обоими случаями.Здесь нет серебряной пули.

...