2017-06-15 128 views
1

檢體執行服務如果線程花費太長時間,如何在執行程序服務中結束線程?

static class MyRunnable implements Runnable { 

    private String serverName; 

    public MyRunnable(String serverName) { 
     super(); 
     this.serverName = serverName; 
    } 

    @Override 
    public void run() { 
     ... 
     conn = new ch.ethz.ssh2.Connection(serverName); 
     conn.connect(); 

     boolean isAuthenticated = conn.authenticateWithPassword(user, pass); 
     logger.info("Connecting to " + server); 

     if (isAuthenticated == false) { 
      logger.info(server + " Please check credentials"); 
     } 

     sess = conn.openSession(); 
     ... 

    } 

} 

public static void main(String[] args) { 
    List<String> serverList = ...; 
    ExecutorService executor = Executors.newFixedThreadPool(20); 

    for (String serverName : serverList) { 
     MyRunnable r = new MyRunnable(serverName); 
     executor.execute(r); 
    } 

    executor.shutdown(); 
    executor.awaitTermination(1, TimeUnit.HOURS); 
} 

就在這裏是我的遺囑執行人服務的示例代碼。但有了這種邏輯,當我遇到無法連接的服務器或連接時間過長時,它會在我的應用程序中創建一個掛起時間。如果連接時間超過x時間,我想結束/終止線程。如果在2秒內沒有連接到服務器,我該如何終止線程任務。

嘗試

 ThreadPoolExecutor executor = new ThreadPoolExecutor(
       10, 25, 500, TimeUnit.MILLISECONDS, 
       new LinkedBlockingQueue<>(1)); 

添加以下代碼,但顯然如果超過2000毫秒時間越長,不結束線程。

嘗試2

Future<?> future = executor.submit(new task)); 
      try { 
       future.get(2000, TimeUnit.MILLISECONDS); // This waits timeout seconds; returns null 
      } 

      catch(TimeoutException e) { 
       future.cancel(true); 
       // System.out.println(server + "name"); 
      } 
+0

關閉另一個線程的連接以導致Runnable中的異常。 – JimmyB

+0

還有另一種使用超時的連接方法。 – assylias

回答

1

如何在2秒內未連接到服務器的情況下終止線程任務。

這很難做到,因爲即使你中斷了線程(就像其他答案中提到的那樣),也不能保證線程會停止。中斷只是在線程上設置一個標誌,並由代碼來檢測狀態並停止。這意味着大量的線程可能在後臺等待連接。

然而,在您的情況下,您正在使用ch.ethz.ssh2.Connection.connect()方法。結果發現有一個connect method that takes a timeout。我想你想以下幾點:

// try to connect for 2 seconds 
conn.connect(null, 2000, 0); 

要從connect method javadocs引用:

在超時的情況下(無論是connectTimeout或kexTimeout)一個SocketTimeoutException被拋出。

+0

我認爲空應該是我的服務器/主機名? API顯示,如果我將它保留爲空,它就是一個優點。 – Jesse

+1

我看到的所有@Jesse都是'connect()'調用和'connect(null,0,0)'相同。我認爲這是一個驗證者。 – Gray

+0

謝謝你,先生。我一直在尋找API,這種方法滑過我的視線。它按預期工作。 – Jesse

0

你要做awaitTermination(),然後再檢查返回值,然後做shutdownNow()shutdown()並不保證服務即時停止,它只是停止採取新的工作,並等待所有工作按順序完成。另一方面,shutdownNow()停止接受新的工作,主動嘗試停止所有正在運行的任務,並且不會啓動任何新的工作,返回所有等待執行的工作列表。

JavaDocs

以下方法關閉在兩個相的ExecutorService, 首先通過調用shutdown拒絕傳入任務,然後調用 shutdownNow時,如果必要的話,取消任何揮之不去的任務:

void shutdownAndAwaitTermination(ExecutorService pool) { 
    pool.shutdown(); // Disable new tasks from being submitted 
    try { 
    // Wait a while for existing tasks to terminate 
    if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { 
     pool.shutdownNow(); // Cancel currently executing tasks 
     // Wait a while for tasks to respond to being cancelled 
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) 
      System.err.println("Pool did not terminate"); 
    } 
    } catch (InterruptedException ie) { 
    // (Re-)Cancel if current thread also interrupted 
    pool.shutdownNow(); 
    // Preserve interrupt status 
    Thread.currentThread().interrupt(); 
    } 
} 
+0

爲什麼-1任何人?答案似乎合法 –

0

您可以隨時調用的Future.get(超時...) 它將返回超時異常,如果它沒有科幻你還可以調用future.cancel()。

0

只要你在Java中處理線程,停止線程的唯一安全方法就是中斷它。您可以先致電shutdown(),然後等待。此方法不會中斷線程。

如果它沒有幫助,那麼您可以撥打shutdownNow(),通過將每個線程的中斷標誌設置爲true來嘗試取消任務。在這種情況下,如果線程被阻塞/等待,則會拋出InterruptedException。如果你在任務內部的任何地方檢查中斷標誌,那麼你也很好。

但是,如果你沒有別的選擇,只能停止線程,你仍然可以做到這一點。獲得訪問工作者的一個可能的解決方案是在自定義線程工廠的幫助下跟蹤ThreadPoolExecutor內的所有創建的線程。

import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.*; 

public class TestThreadPoolEx { 

    static class CustomThreadFactory implements ThreadFactory { 
     private List<Thread> threads = new ArrayList<>(); 

     @Override 
     public Thread newThread(Runnable r) { 
      Thread t = new Thread(r); 
      threads.add(t); 
      return t; 
     } 

     public List<Thread> getThreads() { 
      return threads; 
     } 

     public void stopThreads() { 
      for(Thread t : threads) { 
       if(t.isAlive()) { 
        try { 
         t.stop(); 
        } catch (Exception e) { 
         //NOP 
        } 
       } 
      } 
     } 
    } 

    public static void main(String[] args) throws InterruptedException { 
     CustomThreadFactory factory = new CustomThreadFactory(); 
     ExecutorService ex = Executors.newFixedThreadPool(1, factory); 
     ex.submit(() -> { 
      while(true); 
     }); 
     ex.shutdown(); 
     ex.awaitTermination(5, TimeUnit.SECONDS); 
     ex.shutdownNow(); 
     ex.awaitTermination(5, TimeUnit.SECONDS); 
     factory.stopThreads(); 
    } 
} 

這肯定是不安全的,但應該符合您的要求。在這種情況下,它可以在(真)循環時停止。取消任務將無法做到這一點。

相關問題