2017-02-22 1 views
0

Я хотел бы создать программу, которая иллюстрирует бегунов марафона с контрольными точками. 5 бегунов создаются и принимают случайное количество времени, чтобы добраться до первой контрольной точки. Бегуны должны остановиться на контрольной точке, пока все остальные бегуны не достигнут контрольно-пропускного пункта. Есть 2 контрольных точки и финишная линия.Как приостановить Runnable, пока другой тот же тип не завершил задачу?

Вот некоторые основные код, который я думал, будет лучшим способом осуществить это:

public class Main { 
public static void main(String[] args) { 
    int i = 1; 
    Runner[] runners = new Runner[5]; 

    //Create 5 Runners 
    for (Runner runner : runners) { 
     runner = new Runner(i++); 
     runner.run(); 
    } 

    //Wait for runners to arrive at 1st checkpoint 
    for (Runner runner : runners) { 
     runner.arrivedAt1stCheckpoint(); 
    } 

    //Wait for runenrs to arrive at 2nd checkpoint 
    for (Runner runner : runners) { 
     runner.arrivedAt2ndCheckpoint(); 
    } 

    //Wait for runners to finish race 
    for (Runner runner : runners) { 
     runner.finishedRace(); 
    } 
}} 

public class Runner implements Runnable { 

    public final int runnerID; 
    Random randomGenerator = new Random(); 

    public Runner(int i) { 
     this.runnerID = i; 
    } 

    @Override 
    public void run() { 
     System.out.printf("Runner %d exists\n", runnerID); 
    } 

    public boolean arrivedAt1stCheckpoint() { 
     sleepThread(); 
     System.out.printf("Runner %d arrived at 1st checkpoint\n", runnerID); 
     return true; 
    } 

    public boolean arrivedAt2ndCheckpoint() { 
     System.out.printf("Runner %d arrived at 2nd checkpoint\n", runnerID); 
     sleepThread(); 
     return true; 
    } 

    public boolean finishedRace() { 
     System.out.printf("Runner %d finished race\n", runnerID); 
     sleepThread(); 
     return true; 
    } 

    private void sleepThread() { 
     try { 
      Thread.sleep(randomGenerator.nextInt(1000)); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(Runner.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    }} 

Очевидно, что это едва структура и я пропускаю кучу вещей, так что я не прошу писать вся программа для меня. Моя главная проблема заключается в том, чтобы каждый экземпляр класса Runner каким-то образом взаимодействовал с другими экземплярами и спал всю программу до тех пор, пока все Бегуны не достигнут контрольных точек. Любые «указатели» помогут, спасибо!

+1

Вы считаете 'CountDownLatch'? – MadProgrammer

+0

Никогда не слышал об этом, я проверю его – OverflowingJava

+1

Возможно, вы захотите попробовать ForkJoinPool. Взгляните на метод invokeAll. –

ответ

1

Вы хотите иметь возможность проверить, когда все бегуны сделали это на контрольно-пропускном пункте. Это может быть сделано путем иметь ряд логических переменных, чтобы следить сделал ли или не ваш Runner это checkpoint1, checkpoint2 и т.д.

public class Runner implements Runnable {  
    private boolean atFirstCheckpoint = false; 
    // ... More checkpoint booleans 
    // ... Rest of the class 

    public boolean hasReachedFirstCheckpoint() { 
     return atFirstCheckpoint; 
    } 
} 

Если держать коллекцию бегунов (Array, ArrayList и т.д.), мы можем затем создать метод, который проверяет, достигли ли все наши бегуны контрольной точки.

public boolean everyoneHasReachedFirstCheckpoint(Runner[] runners) { 
    for (Runner r : runners) { 
     if (!r.hasReachedFirstCheckpoint()) { 
      return false; 
     } 
     return true; 
    } 
} 

После этого мы можем изменить нашу прибытую функциюAt1stCheckpoint() для реализации этой проверки. Объект Runner будет спать, пока все остальные бегуны в вашем массиве также не достигнут контрольной точки.

public boolean arrivedAt1stCheckpoint(Runner[] runners) { 
    this.atFirstCheckPoint = true; 
    System.out.printf("Runner %d arrived at 1st checkpoint\n", runnerID); 
    while (!everyoneHasReachedFirstCheckpoint(runners)) { 
     sleepThread(); 
    } 

    return true; 
} 

Edit: Это стоит иметь в виду, что во время выполнения цикла в то время как весь бегун поток будет остановить для X количество времени, в зависимости от вашего sleepThread() метод. Это означает, что бегун буквально будет спать за X промежуток времени, прежде чем он проверит, все ли сделали его на контрольно-пропускном пункте, что вполне может привести к тому, что другие потоки начнут начаться.

Редактировать: Чтобы попытаться управлять своими бегунами (нитями), вы можете использовать интерфейс Executor и/или пулы потоков полезными.

1

Возможно, вы захотите рассмотреть CyclicBarrier или CountDownLatch. Вот быстрый фрагмент с использованием CyclicBarrier.

Установите барьер для требуемого счета вы хотите, пройти барьер вместе с нитями, которые вы хотите ждать на барьере, что-то вроде этого

int BarrierCount = 4; 
CyclicBarrier barrier = new CyclicBarrier(BarrierCount); 

for (int i = 0; i <= BarrierCount; i++) { 
    (new AppThreadsForBarrier(barrier, "name"+i, ...)).start(); 
} 

Сейчас в резьбе, что нужно ждать от барьера, то как ниже может быть сделано

class AppThreadsForBarrier extends Thread { 

    // barrier along with other variables you need for your thread 
    public AppThreadsForBarrier(CyclicBarrier barrier, String name, ....) { 
    .. 

    public void run() { 
     try { 
      Thread.sleep(duration); 
      System.out.println(Thread.currentThread().getName() + " is calling await()"); 
      barrier.await(); 
      System.out.println(Thread.currentThread().getName() + " has started running again"); 
      .. 

Есть некоторые нюансы в отношении которых использовать CyclicBarrier в/с CountdownLatch, но это должно дать вам изображение, чтобы начать работу.

Смежные вопросы