#java #loops #user-interface #command #actionevent
#java #циклы #пользовательский интерфейс #команда #actionevent
Вопрос:
Я работаю над текстовой игрой с графическим интерфейсом в качестве «консоли» для ввода и вывода. Моя цель состоит в том, чтобы, когда игра попросит об этом, отправить команду, которую я ввел в JTextArea, другому методу.
Для этого мне пришла в голову такая идея: при вызове user.readLine()
выполняется цикл до тех пор, пока графический интерфейс не получит событие action. Обнаружение этого события выполняется путем переключения вызываемого логического значения commanded
, переключаемого в методе actionevent. readLine()
затем прерывает цикл на этом этапе и возвращает только что введенный текст, затем возвращает логическое значение обратно. Интересно, что это работает, только если я добавляю System.out.println();
или a Thread.sleep(1);
перед возвратом логического значения обратно…
readLine()
Метод включает в себя много циклов без кода между фигурными скобками, поскольку он ожидает события Action. Неправильно ли думать об этом как о «коротком замыкании» и о чем-то, чего следует избегать? Код приведен ниже. Спасибо!
CommandInput.java:
public void waitForCommand() {
try {
processCommand(Parasite.user.readLine().toLowerCase());
} catch (Exception e) {
System.err.println(e);
}
}
UI.java (инициализируется как Parasite.user):
boolean commanded= false;
String command = "";
public final String readLine()
{
while(commanded == false)
{
System.err.print(command);
}
System.out.println("Submitting Command");
commanded = false;
return command;
}
private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {
commanded=true;
command=jTextField1.getText();
System.err.println(jTextField1.getText());
jTextField1.setText("");
}
Комментарии:
1. Да, это плохо. Попробуйте вместо этого реализовать что-нибудь, основанное на событиях.
2. Когда у вас есть цикл, который постоянно вращается, вы, по сути, сжигаете одно ядро процессора только для ожидания. Кроме того, нет ограничений на то, сколько времени потребуется, чтобы изменение переменной было обнаружено другим потоком.
Ответ №1:
Проблема с коротким замыканием: циклы, которые мало что делают в словах, отличных от цикла, подобного этому:
while(true) {}
не очень удобны для процессора, гораздо лучше было бы что-то вроде этого:
while(true) {
Thread.yield();
}
Это говорит процессору, что этот поток может быть остановлен прямо сейчас, чтобы другие потоки могли выполняться сейчас, он перемещается вниз в очереди потоков. При этом вы не теряете такой уж большой точности, но это мешает вам использовать весь ваш процессор. (смотрите здесь для получения дополнительной информации:http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#yield () )
Итак, в вашем случае:
while(commanded == false)
{
System.err.print(command);
Thread.yield();
}
Комментарии:
1. В статьях, которые я читал об этом, говорится, что поток. обычно не следует использовать yield (), потому что большую часть времени он работает не так, как должен. На что мне следует обратить внимание в результатах профилирования, чтобы убедиться, что оно работает так, как должно быть?
Ответ №2:
Прочитайте эту статью о том, как использовать программирование, управляемое событиями, для решения вашей проблемы. Короче говоря, ваш подход неэффективен и плохо масштабируется
Комментарии:
1. Спасибо за ссылку. Я собираюсь предположить, что любой подход к программированию, основанному на событиях, был бы лучше того, что у меня есть прямо сейчас, поэтому я думаю, что мне нужно изучить и другие методы, чтобы найти лучший для моего проекта.