Старому программисту на 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, один совет: начинайте без потоков, просто используйте неблокирующий ввод-вывод. Тогда - только после того, как все работает правильно - рассмотрите возможность использования нескольких потоков. И делайте это только если у вас проблемы с производительностью.

Другие вопросы по тегам