В многопоточности: как определить, какой поток останавливается первым - PullRequest
5 голосов
/ 01 августа 2010

Напишите класс с именем RaceHorse, расширяющий Thread. Каждый RaceHorse имеет метод name и run (), который отображает имя 5000 раз. Напишите приложение Java, которое создает 2 объекта RaceHorse. Последним, кто закончит 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+" finished.");
    }
}

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();
    }
}

Теперь моя проблема в том, что я не могу определить, какая нить заканчивается первой и какие секунды, то есть какая из лошадей выигрывает, а какая проигрывает.!

Ответы [ 8 ]

11 голосов
/ 01 августа 2010

Прежде всего: ваши RaceHorse объекты сами являются потоками.Вы должны быть в состоянии сказать obj.start();, и это сработало бы так же хорошо.Так что полностью удалите t и t2.

Далее вам понадобится какой-то способ уведомить главный поток о победителе.

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!");
    }
}
6 голосов
/ 01 августа 2010

Нет сомнений, что есть лучший способ, но одним из методов может быть создание класса (например, «Trophy»), который является потокобезопасным, имеет метод «getTrohpy», который возвращает значение true только при первом вызове и передает ссылку наэкземпляр трофея в обоих потоках.

1 голос
/ 01 августа 2010

Как указал cHao, RaceHorse расширяет Thread, но вы создаете новый Thread на лошадь.Я бы решил эту проблему противоположным образом: вместо RaceHorse внедрить Runnable.

Во-вторых, будет работать решение, использующее метод synchronized, но общим правилом всегда является поиск класса в java.util.concurrent это решит проблему первым.Эту проблему можно решить, используя AtomicReference, чтобы гарантировать, что только одна лошадь получает трофей.

Наконец, возможен уклон в пользу лошади # 1, если основной поток запускает потоки лошадей вфиксированный порядок (это зависит от ВМ и от накладных расходов на запуск нового потока в вашей ОС.) Подумайте об использовании сигнала (например, CountDownLatch), которого все лошади ждут перед запуском.

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();
        }
    }

}
1 голос
/ 01 августа 2010
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."); 
    } 
} 
0 голосов
/ 30 июля 2013
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 голосов
/ 08 марта 2012

Я опоздал на вечеринку, но нашел это, когда искал, как обработать первый результат из ряда запущенных потоков. Я думаю, что самый простой способ - использовать ArrayBlockingQueue, который дает вам что-то вроде этого.

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?");
        }
    }
}
0 голосов
/ 01 августа 2010

Это будет работать в конце основного:

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,
   }
}
0 голосов
/ 01 августа 2010

Я не собираюсь писать код для вас; но вы должны взглянуть на метод notify (см. здесь ), который будет использоваться.

Один из подходов может быть следующим: после завершения потока он будет wait() уведомлять другие потоки (или notifyAll()).

Другое, более элегантное решение, состоит в использовании блока synchronized для общего объекта; оператор syncrhonized(obj) будет в конце метода run (). В это утверждение вы можете поместить печатную строку или любой другой код, который вы считаете полезным, чтобы определить, кто выиграл гонку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...