簡體   English   中英

Java中的動態計划並行任務執行

[英]Dynamic Scheduled Concurrent Task Execution in Java

我正在嘗試實現一個基於某些用戶輸入對任務進行編程的應用程序。 用戶可以通過與IP地址關聯的telnet命令(一對一關系),執行頻率和2個組(集群,objectClass)來放置多個IP。

用戶應該能夠在運行時添加/刪除IP,群集,命令等。 他們還應該能夠中斷執行。

該應用程序應該能夠將telnet命令發送到IP,等待響應並將響應基於頻率保存在數據庫中。 我遇到的問題是嘗試使所有這些都成為多線程,因為telnet至少有60,000個IP,而在單個線程中完成將花費太多時間。 一個線程應在同一集群中使用相同的objectClass處理一組IP。

我看過Quartz來安排工作。 使用Quartz,我嘗試進行一個動態工作,該工作需要一個IP列表(帶有命令),對其進行處理並將結果保存到數據庫中。 但是后來我遇到了用戶給定的不同計時器的問題。 Quartz網頁上的示例是不完整的,並且不會太詳細。

然后,我嘗試使用Java Threads以老式的方式進行操作,但是我需要進行異常處理和參數傳遞,而Threads不這樣做。 然后我發現了Callables和Executors,但是我無法安排Callables的任務。

所以現在我很困惑,我該怎么辦?

好,這里有一些想法。 服用必要的鹽粒。

首先,創建所需要做的所有工作的清單。 我假設您在某處的表中有此連接,並且可以進行如下所示的連接:

cluster | objectClass | ip-address | command | frequency | last-run-time

這代表了系統需要完成的所有工作。 為了說明起見,我將說頻率可以采取“每天1次”,“每小時1次”,“每小時4次”,“每分鍾”的形式。 該表每行有一行(集群,objectClass,ip地址,命令)。 假設另一個表具有運行歷史,並帶有錯誤消息和其他內容。

現在您需要做的就是閱讀該表,並安排工作。 要進行調度,請使用以下方法之一:

ScheduledExecutorService exec = Executors...

當您安排某事時,您需要告訴它多久運行一次(使用我們給定的頻率就足夠容易了)和一個延遲。 如果某件事每分鍾運行一次,並且最后一次運行是在30分鍾前4分鍾,那么初始延遲為零。 如果每小時要運行一些東西,則初始延遲為(60分鍾-4.5分鍾= 55.5分鍾)。

ScheduledFuture<?> handle = exec.scheduleAtFixedRate(...);

更復雜的調度類型是為什么存在Quartz之類的原因,但是基本上,您只需要一種方法即可解決(調度,上次運行)下一次執行所花費的時間。 如果可以這樣做,則可以使用schedule(...)而不是scheduleAtFixedRate(...),然后在該任務完成時安排任務的下一次運行。

無論如何,當您安排一些事情時,您將得到回饋。

ScheduledFuture<?> handle = exec.scheduleAtFixedRate(...);

握住此把手以方便使用。 為了論證,我們假設它是TaskKey的地圖。 TaskKey是(群集| objectClass | ip地址|命令)一起作為對象。

Map<TaskKey,ScheduledFuture<?>> tasks = ...;

您可以使用該句柄來取消和安排新作業。

cancelForCustomer(CustomerId id) {
  List<TaskKey> keys = db.findAllTasksOwnedByCustomer(id);
  for(TaskKey key : keys) {
    ScheduledFuture<?> f = tasks.get(key);
    if(f!=null) f.cancel();
  }
}

對於參數傳遞,創建一個對象來代表您的工作。 使用所需的所有參數創建其中之一。

class HostCheck implements Runnable {
  private final Address host;
  private final String command;
  private final int something;
  public HostCheck(Address host, String command; int something) {
    this.host = host; this.command = command; this.something = something;
  }
  ....
}

為了進行異常處理,請將所有內容本地化到您的對象中

class HostCheck implements Runnable {
  ...
  public void run() {
    try {
      check();
      scheduleNextRun(); // optionally, if fixed-rate doesn't work
    } catch( Exception e ) {
      db.markFailure(task); // or however.
      // Point is tell somebody about the failure.
      // You can use this to decide to stop scheduling checks for the host
      // or whatever, but just record the info now and us it to influence
      // future behavior in, er, the future.
    }
  }
}

好的,到目前為止,我認為我們的狀態還不錯。 需要填寫很多細節,但感覺很容易處理。 現在我們有了一些復雜性,那就是要求“ cluster / objectClass”對的執行是串行的。

有兩種方法可以解決此問題。

如果唯一對的數量很少,則可以使Map<ClusterObjectClassPair,ScheduledExecutorService> ,確保創建單線程執行器服務(例如Executors.newSingleThreadScheduledExecutor() )。 因此,您沒有一堆調度服務(上面的exec ),而是一堆。 很簡單。

如果您需要控制同時嘗試的工作量,則可以讓每個HealthCheck在執行之前獲得許可。 有一些全球許可對象

public static final Semaphore permits = java.util.concurrent.Semaphore(30);

接着

class HostCheck implements Runnable {
  ...
  public void run() {
    permits.acquire()
    try {
      check();
      scheduleNextRun();
    } catch( Exception e ) {
      // regular handling
    } finally {
      permits.release();
    }
  }
}

每個ClusterObjectClassPair只具有一個線程,該線程可序列化該工作,然后僅限制ClusterObjectClassPair可以交談的ClusterObjectClassPair

我想這使答案相當長。 祝好運。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM