java передача информации между Thread

Есть JTextField, который хочу заполнить данными извне. Но если сервер не доступен, не хочу, чтоб зависло все приложение. Поэтому попытался заполнять его из другого потока, но явно что-то в этом не разбираюсь. И ничего не работает) Подскажите, куда глядеть. сейчас реализовано так:

final JTextField weightB = new JTextField();
getBruttoFBd(barcode, weightB);
weightB.setBounds(weightF.getX() + weightF.getWidth() + 10, weightF.getY(), 50, 20);
weightB.setEditable(false);

Сам метод для другого потока:

public void getBruttoFBd(final String barcode, final JTextField weightB) {
    Thread mainThread = Thread.currentThread();
    Thread t = new Thread(new Runnable() {
        public void run() {
            String t = "0";
            t = SkSocket.patterString("getweight:"+barcode);
            if(t.equals("0")) {
                weightB.setText("База недоступна");
            } else {
                weightB.setText(t);
            }
        }
    });
    t.interrupt(); // В моем понимании должно уничтожить поток, если все ок) но это не точно
}

Ответы (1 шт):

Автор решения: Roman Konoval

В этом коде две проблемы.

  1. Неправильное использование Thread.interrupt()
  2. Вызов GUI кода из не-GUI потока.

Thread.interrupt()

Thread.interrupt() нужен, чтоб послать потоку прерывание, которое обычно используется, чтоб попросить поток завершить работу. В вашем случае, это не нужно, так какой вызов, скорее всего (это зависит от устройства метода patterString) попросту прервет вызов и поток завершит работу не получив никакого значения и не обновив поле weightB.

Поток завершится, когда исполнение функции run дойдет до конца. Ситуация, когда вам может понадобиться interrupt(), это если вызов patterString заблокируется надолго. В этом случае поток t просто будет заблокирован. На приложение это будет влиять только таким образом, что если вызывать этот код много много раз, то закончится память у приложения.

Поэтому по-хорошему, делают грубо говоря отдельную кнопку, по нажатию на которую потоку t посылается interrupt(). Но это нужно делать не в getButtonFBd, а именно по отдельному событию, например, кнопку которую пользователь может нажать или по таймеру. Опять же, это будет работать, только если patterString обрабатывает interrupt() правильно (т.е. прерывает свою работу и бросает исключение InterruptedException).

Вызовы GUI кода из не-GUI потока

Вторая проблема, это попытка взаимодействовать с GUI компонентами из потока t. Это делать нельзя. Изменять компоненты можно только из потока, в котором запущен цикл обработки событий.

Обработчик, скажем, нажатия на кнопку уже запущен в GUI потоке и там можно это делать напрямую - вызывая методы у GUI объектов. В вашем же случае, когда запущен отдельный поток, можно воспользоваться методами из класса SwingUtilities:

    Thread t = new Thread(new Runnable(){
        public void run(){
            String t = "0";
            t = SkSocket.patterString("getweight:"+barcode);
            if(t.equals("0")) {
                t = "База недоступна";            
            }
            SwingUtilities.invokeAndWait(() -> weightB.setText(t));
        }
   });

В SwingUtilities.invokeAndWait передается функция, которая будет вызвана в GUI потоке, как только он освободится, если в данный момент он занят.

→ Ссылка