управление потоком потоков - PullRequest
1 голос
/ 14 апреля 2010

У меня была задача написать простую игру, имитирующую двух игроков, собирающих по 1-3 матча один за другим, пока куча не исчезнет. Мне удалось сделать это для компьютера, выбирающего случайные значения совпадений, но теперь я хотел бы пойти дальше и позволить людям играть в игру. Вот что у меня уже есть: http://paste.pocoo.org/show/201761/

Класс Player - это компьютерный плеер, а PlayerMan должен быть человеком. Проблема в том, что поток PlayerMan должен ждать, пока не будет задано правильное значение совпадений, но я не могу заставить его работать таким образом. Логика такова: поток работает, пока совпадения не станут равны нулю. Если номер игрока правильный на данный момент, вызывается функция pickMatches (). После уменьшения количества совпадений в таблице поток должен ждать, а другой поток должен быть уведомлен. Я знаю, что должен использовать wait () и notify (), но не могу их правильно разместить. Class Shared сохраняет значение текущего игрока, а также количество совпадений.

public void suspendThread() {
    suspended = true;
}

public void resumeThread() {
    suspended = false;
}

@Override
public void run(){
    int matches=1;
    int which = 0;
    int tmp=0;
    Shared data = this.selectData();
    String name = this.returnName();
    int number = this.getNumber();

    while(data.getMatches() != 0){

        while(!suspended){

            try{             
                which = data.getCurrent();

                if(number == which){

                    matches = pickMatches();

                    tmp = data.getMatches() - matches;
                    data.setMatches(tmp, number);

                    if(data.getMatches() == 0){
                        System.out.println("                          "+
                            name+" takes "+matches+" matches.");
                        System.out.println("Winner is player: "+name);
                        stop();
                    }

                    System.out.println("                          "+
                            name+" takes "+matches+" matches.");

                    if(number != 0){
                        data.setCurrent(0);
                    }
                    else{
                        data.setCurrent(1);
                    }
                }
                this.suspendThread();
                notifyAll();
                wait();

            }catch(InterruptedException exc) {}    
        }
    }
}

@Override
synchronized public int pickMatches(){
    Scanner scanner = new Scanner(System.in);
    int n = 0;
    Shared data = this.selectData();

    System.out.println("Choose amount of matches (from 1 to 3): ");

        if(data.getMatches() == 1){
            System.out.println("There's only 1 match left !");
            while(n != 1){
                n = scanner.nextInt();
            }
        }
        else{
            do{
                n = scanner.nextInt();
            }
            while(n <= 1 && n >= 3);
        }
    return n;
}

}

Ответы [ 3 ]

1 голос
/ 15 апреля 2010

Хорошо, мне удалось сделать это без wait () и т. Д.

http://paste.pocoo.org/show/201966/

1 голос
/ 15 апреля 2010

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

В этом случае рассмотрим один поток, выполняющий метод takeTurn () для различных расширений класса Player, который может облегчить вам жизнь. Вы можете сделать Player абстрактным базовым классом, который требует .takeTurn (), а затем классы HumanPlayer и MachinePlayer инкапсулируют код, который имеет смысл для каждого типа проигрывателя внутри этого метода. Это должно сделать расширение на большее количество игроков относительно тривиальным по сравнению с большим количеством wait () и notify ().

1 голос
/ 14 апреля 2010

Хорошо, позвольте мне сначала сказать, что я думаю, что вы делаете это более жестко, чем нужно. Если бы это был я, я бы создал класс GameMaster, работа которого заключается в том, чтобы зацикливаться и сообщать каждому игроку, когда наступает его очередь. Ваши классы игроков не будут иметь петель, просто метод takeTurn. Таким образом, вы можете удалить поведение ожидания / уведомления из ваших классов игроков.

Если вы хотите сохранить свой дизайн, я все равно избавлюсь от ожидания / уведомления и использую семафор . Проверьте правильность использования документации, но суть в том, что вы удалили бы методы suspend / resume и получили бы вызов acqu () в верхней части цикла, а затем отпустили внизу. Просто убедитесь, что в конструкторе установлено значение true, чтобы вам не пришлось беспокоиться о том, что игрок делает два хода подряд, получая блокировку семафора два раза подряд.

...