2017-02-22 62 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類的每個實例以某種方式與其他實例進行通信,並且休眠整個程序,直到所有Runners達到檢查點。 任何「指針」將有所幫助,謝謝!

+1

你有沒有考慮過'CountDownLatch'? – MadProgrammer

+0

從來沒有聽說過,我會檢查出來 – OverflowingJava

+1

你可能想嘗試一個ForkJoinPool。看看invokeAll方法。 –

回答

1

您想要一種能夠檢查所有跑步者何時進入檢查點的方法。這可能是由於不必跟蹤您的亞軍是否已經做了它對checkpoint1,checkpoint2等

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

    public boolean hasReachedFirstCheckpoint() { 
     return atFirstCheckpoint; 
    } 
} 

如果我們堅持跑步的集合(數組,ArrayList中,等一些布爾變量來完成),我們可以創建一個方法來檢查我們所有的跑步者是否都到達了檢查點。

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

然後,我們可以更改我們的arriveAt1stCheckpoint()來執行此檢查。 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; 
} 

編輯:這是值得記住的是,while循環的執行過程中,整個亞軍線程將停止爲根據您的sleepThread()方法的時間X量。這意味着一名跑步者在檢查是否每個人都進入檢查點之前會在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 v/S CountdownLatch但是這應該給你上手的圖片。

相關問題