2013-08-27 16 views
0

我很難嘗試以我想要的方式正確編程我的應用程序。Java多線程 - 更好的方式取消數據庫和http連接的未來任務?

當前,我的應用程序(作爲Java Servlet)將查詢數據庫以查找要處理的項目列表。對於列表中的每個項目,它都會提交一個HTTP Post請求。我試圖創建一種方法,在用戶請求的情況下,我可以停止此處理(甚至終止進行中的HTTP Post請求)。可以有同時處理不同查詢的線程。現在,我將停止在所有線程中處理。

我目前的嘗試涉及在Callable類中實現數據庫查詢和HTTP Post。然後,我通過Executor服務提交Callable類以獲取Future對象。

但是,爲了正確停止處理,我需要中止HTTP Post並關閉數據庫的Connection,Statement和ResultSet - 因爲Future.cancel()不會爲我做這件事。如何在Future對象上調用cancel()時如何執行此操作?我是否必須存儲包含Future對象,HttpPost,Connection,Statement和ResultSet的數組列表?這似乎有點矯枉過正 - 肯定還有更好的辦法嗎?

這裏是我現在只有中止HttpPost(而不是任何數據庫對象)的代碼。

private static final ExecutorService pool = Executors.newFixedThreadPool(10); 
public static Future<HttpClient> upload(final String url) { 
    CallableTask ctask = new CallableTask(); 
    ctask.setFile(largeFile); 
    ctask.setUrl(url); 
    Future<HttpClient> f = pool.submit(ctask); //This will create an HttpPost that posts 'largefile' to the 'url' 
    linklist.add(new tuple<Future<HttpClient>, HttpPost>(f, ctask.getPost())); //storing the objects for when I cancel later 
    return f; 
} 


//This method cancels all running Future tasks and aborts any POSTs in progress 
public static void cancelAll() { 
    System.out.println("Checking status..."); 

    for (tuple<Future<HttpClient>, HttpPost> t : linklist) { 
     Future<HttpClient> f = t.getFuture(); 
     HttpPost post = t.getPost(); 
     if (f.isDone()) { 
      System.out.println("Task is done!"); 
     } else { 
      if (f.isCancelled()) { 
       System.out.println("Task was cancelled!"); 
      } else { 
       while (!f.isDone()) { 
         f.cancel(true); 
         try { 
          Thread.sleep(5000); 
         } catch (InterruptedException e) { 
          e.printStackTrace(); 
         } 
         System.out.println("!Aborting Post!"); 
         try { 
          post.abort(); 
         } catch (Exception ex) { 
          System.out.println("Aborted Post, swallowing exception: "); 
          ex.printStackTrace(); 
         } 

       } 
      } 
     } 
    } 
} 

有沒有簡單的方法或更好的設計?現在我終止所有處理線程 - 將來,我想終止個別線程。

回答

1

我認爲保留所有要關閉的資源列表並不是最好的方法。在您當前的代碼中,似乎HTTP請求由CallableTask發起,但關閉由其他人完成。在我看來,關閉資源是開放資源的責任。

我會讓CallableTask發起HTTP請求,連接到數據庫,並做它的東西,當它完成或中止時,它應該關閉它打開的所有東西。通過這種方式,您只需跟蹤代表當前正在運行的任務的Future實例。

+0

這使得設計感更好!但是,在調用Future.cancel()時,「CallableTask」如何知道它何時中止?我無法繞開這個念頭。看起來我需要跟蹤其他對象,除了'Future' –

+1

@curious_george,你必須檢查你當前線程在任務中的'interrupt'標記,'Future.cancel(true)'將試圖停止那樣,看到這[回答](http://stackoverflow.com/a/11387729/594406)。 – Katona

0

我認爲你的方法是正確的。當您取消線程時,您需要自己處理回滾

cancel()只是爲正在執行的線程調用interrupt()。看看這裏

http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html

,因爲它說

中斷是指示一個線程,它應該停止它 正在做和做別的事情。由程序員決定 究竟是一個線程如何響應中斷,但是線程終止的非常常見的是 。

中斷線程會拋出InterruptedException

當一個線程在等待,睡覺,或以其他方式暫停了很長的時間 和使用中斷()方法 Thread類是另一個線程中斷

因此,您需要明確地編寫場景,例如您在執行線程時提到的可能會中斷的場景。