2011-03-08 41 views
1

我有一個java客戶端,它正在新線程中管理其服務器調用,以防止GUI凍結。在調用EJB方法時中斷客戶端線程的正確方法是什麼?

即使在許多地方阻止了這種情況,也有可能在同一模型上再次調用該方法,例如使用不同的參數。在這種情況下,我顯然希望具有最新參數的最新呼叫成爲「成功」並顯示其結果的呼叫。

我有一個系統跟蹤之前啓動的線程,並在啓動新線程之前中斷它(Thread.interrupt())。然後,其他方法檢查它們是否在未中斷的線程中運行(使用if (Thread.currentThread().isInterrupted()),然後將新結果發佈到GUI元素。

該結構正在使用以前的連接器到服務器,因爲我是唯一一個檢查進程中的中斷標誌。我的問題是,我現在在客戶端使用EJB方法調用,並且他們對中斷的線程反應不佳。在EJB調用期間中斷線程將觸發RuntimeException,其中包括InterruptedException。這似乎不是一個正常的事情發生。

顯然,我可以在每個服務器調用中捕獲RuntimeExceptions並檢查它們的中斷原因,但它看起來不是很「乾淨」。

我的問題是:在這種情況下我能做些什麼?中斷運行EJB方法調用的線程的正確方法是什麼?

+0

不要緊,要的EJB新過時調用完成?或者你真的需要真正停止EJB端的處理嗎? – Rich 2011-03-08 10:57:47

+0

@Rich - 這其實並不重要。停止它會更好,但是在服務器端需要一個更大的結構,最有可能的是消息傳遞。對於這個問題,我只關注客戶端。 – Gnoupi 2011-03-08 11:03:01

回答

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給出one of the solutions

0

要停止,您需要執行2類的行動螺紋:

  • 如果線程在等待阻塞操作(IO,網絡,鎖定......),你需要interupt它。將會拋出一個InterruptedException,讓運行的代碼有機會捕獲異常並以正確的方式停止。
  • 如果線程只是做了一些處理,Thread.interrupt()將無濟於事。不會拋出異常,線程將繼續處理。處理代碼需要定期檢查您是否仍希望該過程繼續。

在任何情況下,要做到這一點,你需要由你的線程運行的代碼,你想停止處理這兩種情況。這裏沒有銀彈。

+0

我已經覆蓋,因爲我每次重處理間檢查,如果線程被中斷,第二種情況,以及前/服務器調用之後。但對於第一點,調用中斷將觸發EJB調用中的RuntimeException。我的問題並不在於知道什麼時候中斷,我已經在管理它,並停止對線程進行任何進一步的處理。我的問題真的在於EJB引發的「新」異常。 – Gnoupi 2011-03-08 11:00:24

1

如果您不介意在服務器上繼續使用過時的EJB調用,爲什麼不允許調用線程自然終止,而是放棄結果,因爲調用已被另一個線程取代?我沒有時間提供示例實現,但是您可能會發現使用Future s和相關的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; 
    } 

} 

這可能會崩潰,燒,但希望它指向你失望的一個調查線索......

+0

謝謝你的廣泛答案。前程(concurrent包)很可能是要走的路,但目前的系統過於廣泛應用於程序重構這一切,因爲它是。我同意這將是處理這個問題的最好方法。 – Gnoupi 2011-03-08 13:52:20

+0

關於第二個例子,我當前的實現實際上是一個抽象類處理線程,而實際的工作是這樣被我的模型實現一個抽象方法。我的問題在於,我有不依賴於同一框架的子模型,它們自己正在處理「dispatchResult」部分。因此,這也需要一些重構(儘管不如第一種解決方案)。 – Gnoupi 2011-03-08 13:54:51

相關問題