2013-05-29 45 views
0

我正在尋找在Java中實現一種產生任務的機制。這項任務實際上並不相關,它可以通過一個線程或新進程來完成。帶有重試和故障轉移的Java線程/進程

我真正需要的是這樣的:

  • 任務可設置爲重試了N次
  • 如果一些討厭的任務範圍內發生的,產生它的母公司是受保護的
  • 兩者的應該從上面抽象出來

有沒有人知道任何可以在Java中做到的框架?

+0

聽起來像你正在尋找[線程](http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html)。他們爲你做這一切。也許是一個[定時器](http://docs.oracle.com/javase/6/docs/api/javax/swing/Timer.html)。 – OldCurmudgeon

+0

我認爲阿卡會解決這個問題。如果有人可以確認,很樂意回答我自己的問題嗎? – imrichardcole

回答

1

如果一些討厭的任務範圍內發生的,產生它的母公司是受保護的

所以我猜你有3種選擇。

  1. 是在另一個進程中運行任務。看到類似Get Java Runtime Process running in background。我不知道一個可以幫助解決這個問題的框架。這個框架沒有太多的代碼可以節省你的代碼。

  2. 在同一個JVM上的另一個線程中運行。見下文。

  3. 在另一個服務器上的另一個進程中運行。您將不得不編寫客戶端/服務器或使用Web框架或RMI執行遠程處理。我不知道任何框架會自動爲你做這件事。

就在同一JVM中運行它而言,我根本不使用框架。我只是在適當的異常處理循環中運行任務:

for (int i = 0; i < retries; i++) { 
    try { 
     doTask(); 
    } catch (Throwable t) { 
     // log the throwable here 
    } 
} 

看起來像一個框架只是太複雜了。如果任務耗盡內存,那麼在另一個線程中運行它將無濟於事,您將不得不產生另一個進程來處理任務。

如果你需要它在後臺運行,那麼@assyliaas關於使用線程池的最初答案是正確的選擇。

+1

事實上 - 我被冠軍奪走了! – assylias

+0

這並不能解決有關保護的問題。什麼是線程去OOM? – imrichardcole

+0

Np老兄。如果他需要它在背景@assylias中運行,你會發現它。 – Gray

1

我一直在想這個問題已經有一段時間了,終於有了一些你認爲有用的東西。

我們的小「框架」的第一部分是Task接口:

public interface Task { 
    void work(); 
    void stop(); 
} 

實現這一點,我們可以建立我們WorkTask

public class WorkTask implements Task { 
    @Override 
    public void work() { 
     // Do something useful... 
     // might throw SomethingNastyHappenedException 
    } 

    @Override 
    public void stop() { 
     // implement as needed e.g. to break inner loops 
    } 

} 

爲了符合您的要求,以便能夠重試這我們創建一個Wrapper類:

public class RetryingTaskWrapper implements Task { 
    private Task wrappedTask; 
    private int maxTries; 
    private boolean running = false; 

    public RetryingTaskWrapper(Task wrappedTask, int maxTries) { 
     this.wrappedTask = wrappedTask; 
     this.maxTries = maxTries; 
    } 

    @Override 
    public void work() { 
     running = true; 
     boolean success = false; 
     int tries = 0; 

     while (running && !success && tries < maxTries) { 
      try { 
       wrappedTask.work(); 
       success = true; 
      } catch (SomethingNastyHappenedException e) { 
       // something nasty happed so retry 
       tries++; 
      } catch (Exception e) { 
       // something even worse happened -> end 
       running = false; 
      } 
     } 

     running = false; 
    } 

    @Override 
    public void stop() { 
     running = false; 
     wrappedTask.stop(); 
    } 
} 

最後,我們需要一些東西來運行我們的任務...

public class TaskRunner implements Runnable { 
    private Thread thread; 
    private Task task; 
    private boolean running = false; 

    public TaskRunner(Task task) { 
     this.task = task; 
    } 

    public synchronized void start() { 
     if (thread != null) { 
      return; 
     } 

     thread = new Thread(this); 
     thread.start(); 
    } 

    @Override 
    public void run() { 
     running = true; 

     if (task != null) { 
      try { 
       task.work(); 
      } catch (Exception e) { 
       // log your exception 
      } 
     } 

     thread = null; 
     running = false; 
    } 

    public void stop() { 
     if (running) { 
      if (task != null) { 
       task.stop(); 
      } 
      if (thread != null) { 
       thread.interrupt(); 
      } 
     } 
    } 
} 

現在,我們有我們需要的就是建立一個TaskRunner並啓動它:如果您要在不重試運行WorkTask一次

WorkTask workTask = new WorkTask(); 
TaskRunner runner = new TaskRunner(new RetryingTaskWrapper(workTask, 5)); 
runner.start(); 

,這也是可能的:

WorkTask workTask = new WorkTask(); 
TaskRunner runner = new TaskRunner(workTask); 
runner.start(); 

如果你想要你甚至可以在無限循環中運行你的WorkTask而不必改變你自己的WorkTask。所有你需要的是創建另一個包裝

public class InfiniteLoopTaskWrapper implements Task { 
    private Task wrappedTask; 
    private boolean running = false; 

    public InfiniteLoopTaskWrapper(Task wrappedTask) { 
     this.wrappedTask = wrappedTask; 
    } 

    @Override 
    public void work() { 
     running = true; 

     while (running) { 
      try { 
       wrappedTask.work(); 
      } catch (SomethingNastyHappenedException e) { 
       // log that something nasty happened 
      } catch (Exception e) { 
       // something even worse happened -> end 
       running = false; 
      } 
     } 
    } 

    @Override 
    public void stop() { 
     running = false; 
     wrappedTask.stop(); 
    } 

} 

並運行它...

WorkTask workTask = new WorkTask(); 
TaskRunner runner = new TaskRunner(new InfiniteLoopTaskWrapper(workTask)); 
runner.start(); 
2

Akka是一個不錯的選擇這個問題。

或者,如果您只是希望在不使用Akka/actors的情況下執行更好的故障處理,則可以嘗試類似Sarge的類似支持重試和故障升級的方式,類似於Akka的監督。