2017-11-23 10 views
0

私は与えられた遅延の後に連続して実行したいワーカースレッドをたくさん持っています。私は、次の動作を実現したいと思います:遅延が発生した後にタスクを順番に実行するようにスケジュールする

DELAY - >ワーカー1 - > DELAY - >ワーカー2 - DELAY - >ワーカー3 - > ...

私はこの解決策を考え出しました

private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); 

があります:ようexecutorServiceが作成された

long delay = 5; 
for(String value : values) { 
    WorkerThread workerThread = new WorkerThread(value); 
    executorService.schedule(workerThread, delay, TimeUnit.SECONDS); 
    delay = delay + 5; 
} 

JavaでExecutorServiceでこれを実現する他の方法はありますか?

+0

あなたはすべての 'delay'を実行し、単一のworkerthreadを持つことができます:この使用を可能に

public class DelayedTask implements Runnable { private final Runnable task; private final DelayQueue<Delayed> waitQueue; private final DelayQueue<Delayed> followerQueue; public DelayedTask(Runnable task, DelayQueue<Delayed> waitQueue, DelayQueue<Delayed> followerQueue) { this.task = Objects.requireNonNull(task); this.waitQueue = Objects.requireNonNull(waitQueue); this.followerQueue = followerQueue; } @Override public void run() { try { waitQueue.take(); try { task.run(); } finally { if (followerQueue != null) { followerQueue.add(new Delay(3, TimeUnit.SECONDS)); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } 

とシンプルな遅れ実装

class Delay implements Delayed { private final long nanos; Delay(long amount, TimeUnit unit) { this.nanos = TimeUnit.NANOSECONDS.convert(amount, unit) + System.nanoTime(); } @Override public long getDelay(TimeUnit unit) { return unit.convert(nanos - System.nanoTime(), TimeUnit.NANOSECONDS); } @Override public int compareTo(Delayed other) { return Long.compare(nanos, other.getDelay(TimeUnit.NANOSECONDS)); } } 

:そして、このクラスを使用して、労働者を飾りますプロセスの待ち行列から 'value'を取り出します。 – Kayaman

+1

あなたの現在のソリューションはスケジューリングの開始に関連して各作業者の開始を遅らせますが、問題のレイアウトでは1人の作業者が終了してから次の作業を開始するまでに一定の遅延が生じます。あなたは本当に欲しいものを明確にすることができますか? – bowmore

+0

@bowmore私の目標は状態マシンをシミュレートすることです。だから、私は労働者と次の仕事の間に一定の遅れがあるだろう。 –

答えて

0

あなたの問題を見て、別の解決策を思いつきました。値が変更可能なキューであると仮定します。ここでは動作するソリューションです。 WorkerThreadを少し修正してそこにコールバックオブジェクトを追加しました。お役に立てれば。

private final Queue<String> values = new LinkedList<>(); 

private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); 

private void start() { 
    AtomicLong delay = new AtomicLong(5); 
    String value = values.poll(); 

    if (value != null) { 
     WorkerThread workerThread = new WorkerThread(value, new OnCompleteCallback() { 
      @Override 
      public void complete() { 
       String valueToProcessNext = values.poll(); 

       if (valueToProcessNext != null) { 
        executorService.schedule(new WorkerThread(valueToProcessNext, this), delay.addAndGet(5), TimeUnit.SECONDS); 
       } 
      } 
     }); 
     executorService.schedule(workerThread, delay.get(), TimeUnit.SECONDS); 
    } 
} 

class WorkerThread implements Runnable { 

    private final String value; 

    private final OnCompleteCallback callback; 

    WorkerThread(String value, OnCompleteCallback callback) { 
     this.value = value; 
     this.callback = callback; 
    } 

    @Override 
    public void run() { 
     try { 
      System.out.println(value); 
     } finally { 
      callback.complete(); 
     } 
    } 
} 

interface OnCompleteCallback { 
    void complete(); 
} 
0

ExecutorServiceを使用する必要がある場合は、解決策以外は何も気になりません。しかし、おそらくCompletableFutureは、同様の動作を提供するが、スケジューリングの開始の代わりにタスクの完了に比べて遅れているより有用な原因を見つけるでしょう。

​​
0

各ワーカー間にDelayQueueを使用できます。

ExecutorService executorService = Executors.newFixedThreadPool(1); 

// .... 

    DelayQueue<Delayed> currentQueue = new DelayQueue<>(); 
    currentQueue.add(new Delay(3, TimeUnit.SECONDS)); 
    for (String value : values) { 
     DelayedTask delayedTask = new DelayedTask(new WorkerThread(value), currentQueue, currentQueue = new DelayQueue<>()); 
     executorService.submit(delayedTask); 
    } 
関連する問題