2017-02-22 97 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但是这应该给你上手的图片。

相关问题