2010-11-19 2 views
2

Я пишу систему тестирования, и я все, что я хочу сделать, это подсчитать, сколько секунд пользователь потратил на этот вопрос. то есть i напечатать вопрос (стандартный System.out.println), а затем подождать 5 секунд, и если в течение этих 5 секунд пользователь ответил (через стандартный ввод), я хочу сохранить это значение. Если пользователь не предоставил ответ в течение 5 секунд, он должен пропустить этот вопрос и продолжить. Проблема заключается в том, что im читает пользовательские ответы через объект Scanner, и что-то вроде in.nextInt() неконтролируемо, я полагаю.Получить ввод в определенное время

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

public void start() { 
    questions.prepareQuestions(numQuestions); 
    Scanner in=new Scanner(System.in); 
    boolean playerIsRight=false,botIsRight=false; 
    int playerScore=0,botScore=0; 
    for (int i = 0; i < numQuestions; i++) { 
     questions.askQuestion(i); 
     System.out.print("Your answer(number): "); 
     playerIsRight=questions.checkAnswer(i,in.nextInt()-1); //in.nextInt() contains the answer 
     botIsRight=botAnswersCorrectly(i + 1); 
     if(playerIsRight){ playerScore++; System.out.println("Correct!");} 
     else System.out.println("Incorrect!"); 
     if(botIsRight) botScore++; 
     System.out.print("\n"); 
    } 
    if(botScore>playerScore) System.out.println("Machine won! Hail to the almighty transistors!"); 
    else if(playerScore>botScore) System.out.println("Human won! Hail to the power of nature!"); 
    else System.out.println("Tie. No one ever wins. No one finally loses."); 
} 

ответ

1

В этом случае я бы использовал две нити. Основной поток задает вопросы, ждет ответов и ведет счет. Детский поток читает стандартный ввод и отправляет ответы на главный поток, возможно, через BlockingQueue.

Основной поток может ждать в течение пяти секунд для ответа с помощью метода poll() на очереди блокировки:

… 
BlockingQueue<Integer> answers = new SynchronousQueue(); 
Thread t = new ReaderThread(answers); 
t.start(); 
for (int i = 0; i < numQuestions; ++i) { 
    questions.askQuestion(i); 
    System.out.print("Your answer (number): "); 
    Integer answer = answers.poll(5, TimeUnit.SECONDS); 
    playerIsRight = (answer != null) && questions.checkAnswer(i, answer - 1); 
    … 
} 
t.interrupt(); 

Если этот вызов возвращает null, основная нить знает, что ребенок нить не получила любой ввод за это время, и может соответствующим образом обновить оценку и распечатать следующий вопрос.

ReaderThread будет выглядеть примерно так:

class ReaderThread extends Thread { 

    private final BlockingQueue<Integer> answers; 

    ReaderThread(BlockingQueue<Integer> answers) { 
    this.answers = answers; 
    } 

    @Override 
    public void run() { 
    Scanner in = new Scanner(System.in); 
    while (!Thread.interrupted()) 
     answers.add(in.nextInt()); 
    } 

} 

использовано на System.in, то Scanner будет блокировать до тех пор, пока пользователь не нажмет Enter, так что может случиться так, что пользователь ввел некоторый текст, но пока не будет нажата Enter когда основной поток истекает и переходит к следующему вопросу. Пользователь должен удалить свою ожидающую запись и ввести новый ответ для нового вопроса. Я не знаю, как это сделать, так как нет надежного способа прерывать вызов nextInt().

+0

Это может быть хромой, но что, если я начну новый поток после вопроса, вызовет wait (timeout), и в новом потоке я буду ждать ответа и после его получения я вызову notify() для объекта в родительский поток. Это будет работать? – Anton

+0

Я только что проверил - его не работает :) – Anton

+0

Вы можете опрокинуть свое собственное решение, используя 'wait' и' notify', но, как вы видели, это сложно сделать правильно. Использование «BlockingQueue» примерно эквивалентно, но оно поставляется в чистом, надежном пакете. – erickson

Смежные вопросы