开发者

In multithreading: How to determine which thread stops first

Write a class named RaceHorse that extends Thread. Each RaceHorse has a name and run() method that displays the name 5000 times. Write a Java application that instantiates 2 RaceHorse objects. The last RaceHorse to finish is the loser.

This is the question. I have written the code for the two classes two run the thread Here are the codes:

RaceHorse

class RaceHorse extends Thread
{
    public String name;
    public RaceHorse(String name)
    {
        this.name = name;
    }
    public void run()
    {
        for(int i = 1 ; i <= 5000; i++)
        {
            System.out.println(i+"  "+name);
        }
        System.out.println(name+" finis开发者_如何学Gohed.");
    }
}

Runner

class Runner{
    public static void main(String args[])
    {
        RaceHorse obj = new RaceHorse("Lol");
        RaceHorse obj2 = new RaceHorse("BOL");
        Thread t = new Thread(obj);
        Thread t2 = new Thread(obj2);
        t.start();
        t2.start();
    }
}

Now my problem is I am unable to find which of the thread finishes first and which seconds, i.e. which of the horse wins and which loses.!


First off: your RaceHorse objects are themselves threads. You should be able to say obj.start(); and it'd work just as well. So remove t and t2 entirely.

Next, you'll need some way to notify the main thread about the winner.

public void run()
{
    ... your loop stuff ...
    // this is how we're going to do the notification.
    Runner.done();
}

public class Runner
{
    private static RaceHorse winner = null;
    synchronized static void done()
    {
        // Threads calling this are going to be RaceHorse objects.
        // Now, if there isn't already a winner, this RaceHorse is the winner.
        if (winner == null) winner = (RaceHorse) Thread.currentThread();
    }

    public static void main(String[] args)
    {
         ... create the horses ...
         // start the horses running
         obj.start();
         obj2.start();

         // wait for them to finish
         obj.join();
         obj2.join();

         System.out.println(winner.name + " wins!");
    }
}


There's no doubt a better way, but one method might be to create a class (e.g. 'Trophy') that is thread safe, has a method 'getTrohpy' that only returns true on the first call, and pass a reference to an instance of Trophy to both threads.


public class StackOverflow {

    public static void main(String[] args) {
         RaceHorse obj = new RaceHorse("Lol"); 
            RaceHorse obj2 = new RaceHorse("BOL"); 
            Thread t = new Thread(obj); 
            Thread t2 = new Thread(obj2); 
            t.start(); 
            t2.start(); 

    }       
    }
class RaceHorse extends Thread 
{ 
    //public String name; 
    public RaceHorse(String name) 
    { 
        this.setName(name); 
    } 
    public void run() 
    { 
        for(int i = 1 ; i <= 5000; i++) 
        { 
            System.out.println(i+"  "+this.getName()); 
            try {
                Thread.sleep(250);
            } catch (InterruptedException e) {

                e.printStackTrace();
            }
        } 
        System.out.println(this.getName()+" finished."); 
    } 
} 


As cHao pointed out, RaceHorse extends Thread but you are creating a new Thread per horse. I would solve it the opposite way, by having RaceHorse implement Runnable instead.

Secondly, the solution using a synchronized method will work, but a general rule is always look for a class in java.util.concurrent that will solve the problem first. This one can be solved using an AtomicReference to ensure that only one horse takes the trophy.

Lastly, there could be a bias in favour of horse #1, if the main thread starts the horses' threads in a fixed order (this depends on the VM and on the overhead of starting a new thread on your OS.) Consider using a signal (for example a CountDownLatch) that all horses wait for before starting.

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;

public class Runner {

    public static void main(String args[]) {
        AtomicReference<RaceHorse> winner =
            new AtomicReference<RaceHorse>();
        CountDownLatch startingPistol = new CountDownLatch(1);
        RaceHorse horse1 = new RaceHorse("Lol", startingPistol, winner);
        RaceHorse horse2 = new RaceHorse("BOL", startingPistol, winner);
        Thread thread1 = new Thread(horse1);
        Thread thread2 = new Thread(horse2);
        thread1.start();
        thread2.start();
        startingPistol.countDown();
    }

}

class RaceHorse implements Runnable {

    private final String name;
    private final CountDownLatch startingPistol;
    private final AtomicReference<RaceHorse> winner;

    public RaceHorse(String                     name,
                     CountDownLatch             startingPistol,
                     AtomicReference<RaceHorse> winner)
    {
        this.name = name;
        this.startingPistol = startingPistol;
        this.winner = winner;
    }

    public void run()
    {
        try {
            startingPistol.await();
            for(int i = 1 ; i <= 5000; i++)
            {
                System.out.println(i+"  "+name);
            }
            boolean iWon = winner.compareAndSet(null, this);
            System.out.printf("%s %s.%n", name, iWon? "won": "lost");
        } catch (InterruptedException ex) {
            System.out.printf("%s was assasinated before the race started.%n", name);
            Thread.currentThread().interrupt();
        }
    }

}


I am not going to write the code for you; but you should take a look at the notify method (see here) to be used.

One approach could be: once a thread has finished it will wait() for the other thread(s) to notify (or notifyAll()).

Another, more elegant solution, would consist of using a synchronized block on a shared object; the syncrhonized(obj) statement would be at the end of the run() method. Into that statement you could put a printline or any other code you would deem useful to determine who won the race.


This will work at the end of the main :

boolean alive1 = true;
boolean alive2 = true;

while (alive1 && alive2) {
   alive1 =  obj.isAlive();
   alive2 =  obj2.isAlive();
   if (!alive1 && !alive2) {
       // Too close to call
   }
   if (!alive1) {
       // obj wins,
   }
   if (!alive2) {
       // obj2 wins,
   }
}


I'm late to the party, but I found this while looking for how to process the first result from a number of running threads. I think the easiest way is to use an ArrayBlockingQueue which gives you something like this.

public class RaceHorse extends Thread {
        private ArrayBlockingQueue<RaceHorse> finishedRaceHorses;

        public RaceHorse(String name) {
            super(name);
        }

        public void run() {
            for (int i = 1; i <= 50; i++) {
                System.out.println(i + "  " + getName());
            }
            System.out.println(getName() + " finished.");

            finishedRaceHorses.offer(this);
        }

        public void setFinishedRaceHorses(ArrayBlockingQueue<RaceHorse> finishedRaceHorses) {
            this.finishedRaceHorses = finishedRaceHorses;
        }
    }

    public class Race {
        private final List<RaceHorse> raceHorses;

        public Race(List<RaceHorse> raceHorses) {
            this.raceHorses = raceHorses;
        }

        public RaceHorse go() throws InterruptedException {
            ArrayBlockingQueue<RaceHorse> finishedRaceHorses = new ArrayBlockingQueue<RaceHorse>(raceHorses.size());
            for (RaceHorse raceHorse : raceHorses) {
                raceHorse.setFinishedRaceHorses(finishedRaceHorses);
                raceHorse.start();
            }

            return finishedRaceHorses.take();
        }
    }

public class Runner {
    public static void main(String args[])
    {
        RaceHorse horseOne = new RaceHorse("Lol");
        RaceHorse horseTwo = new RaceHorse("BOL");

        Race race = new Race(Arrays.asList(horseOne, horseTwo));
        try {
            RaceHorse winner = race.go();
            System.out.println("The winner is " + winner.getName());
        } catch (InterruptedException e) {
            System.out.println("The race was interrupted, maybe by a streaker?");
        }
    }
}


I have tried this problem and solved it using following code. There is room for improvement but for me this code worked perfectly :

1.RacingGame.java
/
package game;

import gamingObject.Horse;
import gamingObject.Race;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class RacingGame {

    /**
     * @param args
     */

    public static Map<Integer, List<String>> raceToWinners = new HashMap<Integer, List<String>>();
    public static int currentRace = 1;
    public static boolean trackComplete = false;
    private static boolean newTrackBegin;
    private static boolean flag = true;
    private static boolean race6Begin = false;
    private static boolean race7Begin = false;
    private static Object mutex = new Object();
    private int frstHorseInNextRace = 0;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService exeService = Executors.newFixedThreadPool(5);
        /*
         * Logic to conduct first 5 races (total horses/total track) so here
         * total horses = 25 and tracks = 5 hence initial and compolsuary races
         */

        RacingGame rg = new RacingGame();

        for (int race = 1; race <= 5; race++) {
            trackComplete = false;
            currentRace = race;
            while (!trackComplete) {
                rg.startTrack();
            }
        }
        /*
         * Before 6th Race lets have right candidate for 6th race
         */
        List<String> horseNames = chooseHorsesForRace6();

        /*
         * Race among 5 tops horses from 5 races
         */
        currentRace++;
        synchronized (mutex) {
            while (!race6Begin) {
                race(horseNames);
            }
        }

        /*
         * Choose candidates for last race 7
         */
        horseNames = chooseHorsesForRace7();

        currentRace++;
        synchronized (mutex) {
            while (!race7Begin) {
                race(horseNames);
            }
        }

        printResults();

        System.exit(0);
    }

    private static void printResults() {
        // TODO Auto-generated method stub
        Iterator<Integer> iter = raceToWinners.keySet().iterator();
        while (iter.hasNext()) {
            int raceNum = iter.next();
            StringBuffer sb = new StringBuffer();
            System.out.println("Race" + raceNum + " : ");
            List<String> horses = raceToWinners.get(raceNum);
            for (int i = 0; i < 3; i++) {
                sb.append(horses.get(i));
                if (i < 2)
                    sb.append(",");
            }
            System.out.print(sb.toString());
            System.out.println();
        }
    }

    private static List<String> chooseHorsesForRace7() {
        /*
         * Adding First horse at first rank among 25 horses
         */
        List<String> winners = new ArrayList<String>();
        winners.add(raceToWinners.get(6).get(0));
        raceToWinners.put(7, winners);
        /*
         * Taking first horses from races 2 and 3
         */
        List<String> finalTrackHorses = new ArrayList<String>();
        finalTrackHorses.add(raceToWinners.get(6).get(1));// firstHorse
        finalTrackHorses.add(raceToWinners.get(6).get(2));// secondHorse
        /*
         * Rejecting all horses from race track whose first horses are at 4th
         * and 5th rank of race 6
         */
        for (int i = 1; i <= 5; i++) {
            if (raceToWinners.get(i).contains(winners.get(0))) {
                finalTrackHorses.add(raceToWinners.get(i).get(1));// thirdHorse
                finalTrackHorses.add(raceToWinners.get(i).get(2));// forth horse
            } else if (raceToWinners.get(i).contains(finalTrackHorses.get(1))) {
                finalTrackHorses.add(raceToWinners.get(i).get(1));// fifth horse
            }
        }
        return finalTrackHorses;
    }

    private static void race(List<String> horseNames) throws InterruptedException {
        if (currentRace == 6)
            race6Begin = true;
        else
            race7Begin = true;
        newTrackBegin = true;
        flag = true;
        trackComplete = false;
        while (flag) {
            if (!trackComplete) {
                /*
                 * Create thread for each horse
                 * 
                 * Here taking slot of 5 horses and keep them running in a
                 * single loop.
                 */
                if (newTrackBegin) {
                    List<String> horses = Arrays.asList(horseNames.get(0),
                            horseNames.get(1), horseNames.get(2),
                            horseNames.get(3), horseNames.get(4));
                    Race r = new Race(horses);
                    r.start();
                }
                newTrackBegin = false;
                mutex.wait(1);

            } else if (trackComplete) {
                mutex.notify();
                flag = false;
            }

        }

    }

    private static List<String> chooseHorsesForRace6() {
        List<String> lstHorses = new ArrayList<String>();
        for (int i = 1; i <= 5; i++) {
            /*
             * Take only 1st Position Holders of first 5 races
             */
            lstHorses.add(raceToWinners.get(i).get(0));
        }
        return lstHorses;
    }

    public Map<Integer, List<String>> getRaceToWinners() {
        return raceToWinners;
    }

    public static synchronized void addTrackWinnerInList(String horseName) {
        List<String> horses = raceToWinners.get(currentRace);
        if (horses == null) {
            List<String> raceHorses = new ArrayList<String>();
            raceHorses.add(horseName);
            raceToWinners.put(currentRace, raceHorses);
        } else {
            horses.add(horseName);
            raceToWinners.put(currentRace, horses);
        }
        if (raceToWinners.get(currentRace) != null
                && raceToWinners.get(currentRace).size() == 5) {
            trackComplete = true;
        }
    }

    public static boolean isTrackComplete(){
        return trackComplete;
    }

    public void startTrack() throws InterruptedException {
        // TODO Auto-generated method stub
        synchronized (mutex) {
            flag = true;
            newTrackBegin = true;
            trackComplete = false;
            while (!trackComplete) {
                /*
                 * Create thread for each horse
                 * 
                 * Here taking slot of 5 horses and keep them running in a
                 * single loop.
                 */
                    if (newTrackBegin) {
                        List<String> horses = Arrays.asList("Horse"
                                + (++frstHorseInNextRace), "Horse"
                                + (++frstHorseInNextRace), "Horse"
                                + (++frstHorseInNextRace), "Horse"
                                + (++frstHorseInNextRace), "Horse"
                                + (++frstHorseInNextRace));
                        Race r = new Race(horses);
                        r.start();
                    }
                    newTrackBegin = false;

            }

        }

    }

}


2.Horse.java

    package gamingObject;

import game.RacingGame;

public class Horse extends Thread{

    String horseName;

    public Horse(String horseName){
        this.horseName = horseName;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        RacingGame.addTrackWinnerInList(this.horseName);
    }

}

3.Race.java

    package gamingObject;

import game.RacingGame;

import java.util.List;

public class Race extends Thread {

    List<String> horses;
    private boolean flag = true;
    private Object obj = new Object();

    public Race(List<String> horses) {
        this.horses = horses;
    }

    public void startRace() {
        synchronized (obj) {
            run();
        }
    }

    @Override
    public void run() {
        synchronized (obj) {
            boolean newTrackBegin = true;

            while (!RacingGame.isTrackComplete()) {
                    /*
                     * Create thread for each horse
                     * 
                     * Here taking slot of 5 horses and keep them running in a
                     * single loop.
                     */
                    if (newTrackBegin) {
                        Horse h1 = new Horse(horses.get(0));
                        Horse h2 = new Horse(horses.get(1));
                        Horse h3 = new Horse(horses.get(2));
                        Horse h4 = new Horse(horses.get(3));
                        Horse h5 = new Horse(horses.get(4));
                        Thread t1 = new Thread(h1);
                        Thread t2 = new Thread(h2);
                        Thread t3 = new Thread(h3);
                        Thread t4 = new Thread(h4);
                        Thread t5 = new Thread(h5);
                        t1.start();
                        t2.start();
                        t3.start();
                        t4.start();
                        t5.start();
                        newTrackBegin = false;
                    }else{
                        if(!RacingGame.isTrackComplete()){
                            try {
                                obj.wait(10);
                            } catch (InterruptedException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                        }else{
                            obj.notify();
                        }

                    }

            }

        }
    }

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜