Старому программисту на C++, новичку на Java, нужна помощь по многопоточности Java и событиям
Я "конвертирую" программу на C++ (точнее, "компонент" Borland), использующую последовательный порт, в Java. Эта программа использует поток для прослушивания последовательного порта и генерирует событие, когда получен один из заданных "символов события" (это может быть "Возврат каретки", "ACK", "NACK...") или когда определенное пользователем число символы получены.
Пытаясь преобразовать его в Java, я немного узнал о потоках, сделав его наполовину рабочим. Мне все еще нужно понять, как вызвать событие из потока прослушивания в основной поток... и затем я узнал о существовании исполнителей, что, кажется, является правильным путем, поскольку пользователь может закрывать, открывать или изменять несколько раз порт и создание нового потока каждый раз кажется плохой практикой.
Итак, перед тем, как провести несколько дней в море параллелизма Java, после такой большой работы, потраченной на "сырые" потоки, я бы попросил совета и, возможно, небольшого примера.
Какой тип объекта (я вижу, что есть различные виды исполнителей) я должен использовать, чтобы иметь последовательный слушатель, который:
- в состоянии бросить событие в основной поток, чтобы передать полученный массив символов
- может быть приостановлено и перезапущено (и это может указывать на другой поток ввода во время приостановки... я имею в виду, что я мог бы вызвать некоторые из его методов, пока приостановлено)
- он будет уничтожен, когда в нем нет необходимости (вместо этого пользователь может использовать сокет, поэтому слушатель больше не понадобится)
? Я действительно не знаю, зависят ли некоторые из этих точек от объекта, который я выберу, поэтому я перечислил их все просто, чтобы избежать повторного выполнения всего в другой раз, потому что мне было неясно.
Благодарю.
2 ответа
Если у вас есть какой-то основной поток, который просто должен получать события из других потоков (так же, как это делает сокет сервера), может быть решена некоторая очередь блокировки. Основной поток может вызвать takeLast
в цикле - это приостановит его, пока любой другой поток не вызовет putFirst
, предлагая значение для той же очереди. ( SynchronousQueue будет останавливать поток предложения до тех пор, пока основной поток не будет готов или, в качестве альтернативы, ArrayBlockingQueue поддерживает очередь заданного размера).
При такой настройке основной поток также не может быть потоком GUI. Используйте invokeAndWait, если вам нужно прикоснуться к компонентам интерфейса, таким как метки или кнопки на нем.
final BlockingQueue q = new ArrayBlockingQueue(3);
new Thread() {
public void run() {
while (have_some_messages()) {
q.putFirst("Hey!");
}
}
}.start();
new Thread() {
public void run() {
while (also_have_some_messages()) {
q.putFirst("Boo!");
}
}
}.start();
// Main thread will print both Hey and Boo:
while (must_keep_running()) {
Object serveIt = q.takeLast();
System.out.println(serveIt);
}
Если основной поток является потоком Swing (вы говорите, JFrame с элементами управления Swing), добавьте туда кнопку для запуска потока обслуживания:
Runnable service = new Runnable() {
public void run() {
try {
while (must_keep_running()) {
Object serveIt = q.takeLast();
System.out.println(serveIt);
}
} finally {
// Re-enable the start button when the service thread exits:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
bStart.setEnabled(true);
}
});
};
}
};
JButton bStart = new JButton("Start ..");
bStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new Thread(service).start();
bStart.setEnabled(false);
}
}
});
Я хотел бы сделать поток переноса порта основанным на синглтоне, возможно, с некоторыми статическими ( синхронизированными!) Средствами доступа.
Хорошим интерфейсом для связи между потоками в вашем случае будет паттерн Listener/Observer - он должен быть достаточно универсальным, чтобы решить вашу проблему.
Поскольку вы новичок в Java, один совет: начинайте без потоков, просто используйте неблокирующий ввод-вывод. Тогда - только после того, как все работает правильно - рассмотрите возможность использования нескольких потоков. И делайте это только если у вас проблемы с производительностью.