Arhn - архитектура программирования

Графический интерфейс Java очень тормозит при обновлении нескольких компонентов из потока

У меня есть простой маленький чат-клиент, я обновляю несколько компонентов графического интерфейса из потока, когда java-клиент получает новое сообщение с сервера.

Вот ветка:

  /*
   * Thread class to listen for message from the server
   */
   class ListenFromServer extends Thread {
       public void run() {
           BufferedReader in = new BufferedReader(new InputStreamReader(is));

           while (true) {
               try {
                   String tmpMsg = in .readLine().replaceAll("\\r\\n|\\r|\\n", "");

                   JSONObject json = new JSONObject(tmpMsg);

                   updateInfo(x,x,x,x,x,x,x,x,x); // Just to show
                   printMsg("hello world", "server", "21:20"); // prints message to JTextPane
                   }
               } catch (Exception e) {
                   e.printStackTrace();
               }
           }
       }
   }

Поэтому, когда сообщение получено, я запускаю следующие две функции:

public void updateVisitorInfo(final String userCountry, final String userCity, final String visits, final String seType, final String seKeyword, final String trafficType, final String currentPage) {

    SwingUtilities.invokeLater(
        new Runnable() {
            public void run() { 
                System.out.println("UPDATE");

                jLabel23.setText(userCountry + ", " + userCity);


                int numberOfVisits = Integer.parseInt(visits);
                if (numberOfVisits <= 1) {
                    jLabel33.setText("<html>First visit</html>");
                } else {
                    jLabel33.setText("<html>Returning visit:<br><b>" + visits + "</b> visits</html>");
                }

                if (trafficType.contains("Direct")) {
                    jLabel43.setText("<html>Came from: Direct hit</html>");
                } else if (trafficType.contains("Organisk")) {
                    jLabel43.setText("<html>Came from: " + seType + "<br />Searched keyword:<br /><b>" + seKeyword + "</b></html>");
                } else if (trafficType.contains("AdWords")) {
                    jLabel43.setText("<html>Came from: AdWords<br />Searched keyword:<br /><b>" + seKeyword + "</b></html>");
                }


                jLabel53.setText("<html><div style='width:140px;'><p>Current:<br /> <a href='" + Page + "'>" + currentPage + "</a></p></div></html>");

            }
        });        
    //jLabel83.setText("<html><div style='padding-left:50px;'>Chat with " + visitorNick + "</div></html>");
}

а также:

public void printMsg(final String msg, final String from, final String tid) {


    SwingUtilities.invokeLater(new Runnable() {
        public void run() {

            if (msg != null && !msg.isEmpty()) {

                String align = "text-align:right;";
                String padd = "padding-left:12px;";
                if (from.contains(agentName)) {
                    align = "text-align:right;";
                    padd = "padding-right:12px;";
                } else {
                    align = "text-align:left;";
                    padd = "padding-left:12px;";
                }

                // Print the message
                try {
                    kit.insertHTML(doc, doc.getLength(), "<div id=\"\" style=\"padding-top:10px;padding-bottom:10px;" + padd + "\">" + "<div id=\"\" style=\"position:relative;" + align + "\"><span style=\"color:#111111;font-weight:bold;\">" + from + "</span> at " + tid + ":</div>" + "<div id=\"\" style=\"padding-top:4px;" + align + "\">" + msg + "</div>" + "</div>", 0, 0, null);
                } catch (BadLocationException ex) {
                    Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IOException ex) {
                    Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                }


                ta.setCaretPosition(ta.getDocument().getLength()); // To scroll to the bottom of the JTextPane

            }
        }
    });

РЕДАКТИРОВАТЬ: JPanels, содержащие компоненты из приведенного выше кода, становятся белыми, поэтому все приложение не зависает, но JPanels становится белым

РЕДАКТИРОВАТЬ 2:

Вот как я начинаю тему:

new ListenFromServer().start();

Этот код выполняется при загрузке JFrame (в пределах init())

ИЗМЕНИТЬ 3:

Выход из jstack <pid>

2013-09-09 16:41:02
Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.51-b01-457 mixed mode):

"Attach Listener" daemon prio=9 tid=7fac0f9d3800 nid=0x112bfd000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Thread-8" prio=5 tid=7fac1107f800 nid=0x112f13000 waiting on condition [112f12000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at Client$SystemIdleThread.run(Client.java:1824)

"Thread-7" prio=5 tid=7fac1107f000 nid=0x112e10000 runnable [112e0f000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at java.io.DataInputStream.read(DataInputStream.java:132)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
    - locked <7f4815550> (a java.io.InputStreamReader)
    at java.io.InputStreamReader.read(InputStreamReader.java:167)
    at java.io.BufferedReader.fill(BufferedReader.java:136)
    at java.io.BufferedReader.readLine(BufferedReader.java:299)
    - locked <7f4815550> (a java.io.InputStreamReader)
    at java.io.BufferedReader.readLine(BufferedReader.java:362)
    at Client$ListenFromServer.run(Client.java:2070)

"DestroyJavaVM" prio=5 tid=7fac0f1b0000 nid=0x1061d7000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"TimerQueue" daemon prio=5 tid=7fac0f1af000 nid=0x1122fa000 in Object.wait() [1122f9000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f481d048> (a javax.swing.TimerQueue)
    at javax.swing.TimerQueue.run(TimerQueue.java:232)
    - locked <7f481d048> (a javax.swing.TimerQueue)
    at java.lang.Thread.run(Thread.java:680)

"AWT-EventQueue-0" prio=6 tid=7fac0e173000 nid=0x111fc6000 in Object.wait() [111fc5000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f459dc30> (a java.awt.EventQueue)
    at java.lang.Object.wait(Object.java:485)
    at java.awt.EventQueue.getNextEvent(EventQueue.java:558)
    - locked <7f459dc30> (a java.awt.EventQueue)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:263)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

"Java2D Disposer" daemon prio=10 tid=7fac0d0de800 nid=0x111ec3000 in Object.wait() [111ec2000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f45cdcf8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <7f45cdcf8> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
    at sun.java2d.Disposer.run(Disposer.java:127)
    at java.lang.Thread.run(Thread.java:680)

"AWT-Shutdown" prio=5 tid=7fac0f229000 nid=0x10e0b0000 in Object.wait() [10e0af000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f45cdd28> (a java.lang.Object)
    at java.lang.Object.wait(Object.java:485)
    at sun.awt.AWTAutoShutdown.run(AWTAutoShutdown.java:265)
    - locked <7f45cdd28> (a java.lang.Object)
    at java.lang.Thread.run(Thread.java:680)

"AWT-AppKit" daemon prio=5 tid=7fac0f0c8800 nid=0x7fff7508a180 runnable [00000000]
   java.lang.Thread.State: RUNNABLE

"Low Memory Detector" daemon prio=5 tid=7fac0f01b000 nid=0x10d9d2000 runnable [00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" daemon prio=9 tid=7fac0f01a800 nid=0x10d8cf000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" daemon prio=9 tid=7fac0f019800 nid=0x10d7cc000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=9 tid=7fac0f019000 nid=0x10d6c9000 runnable [00000000]
   java.lang.Thread.State: RUNNABLE

"Surrogate Locker Thread (Concurrent GC)" daemon prio=5 tid=7fac0f018000 nid=0x10d5c6000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=8 tid=7fac0f00d000 nid=0x10d338000 in Object.wait() [10d337000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f45cdd40> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <7f45cdd40> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:171)

"Reference Handler" daemon prio=10 tid=7fac0f00c800 nid=0x10d235000 in Object.wait() [10d234000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <7f4899298> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:485)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
    - locked <7f4899298> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=9 tid=7fac0f008000 nid=0x10d132000 runnable 

"Gang worker#0 (Parallel GC Threads)" prio=9 tid=7fac0d003800 nid=0x1095da000 runnable 

"Gang worker#1 (Parallel GC Threads)" prio=9 tid=7fac0d004800 nid=0x1096dd000 runnable 

"Gang worker#2 (Parallel GC Threads)" prio=9 tid=7fac0d005000 nid=0x1097e0000 runnable 

"Gang worker#3 (Parallel GC Threads)" prio=9 tid=7fac0d005800 nid=0x1098e3000 runnable 

"Concurrent Mark-Sweep GC Thread" prio=9 tid=7fac0e07a800 nid=0x10cda9000 runnable 
"VM Periodic Task Thread" prio=10 tid=7fac0f02c800 nid=0x10dad5000 waiting on condition 

"Exception Catcher Thread" prio=10 tid=7fac0d003000 nid=0x106402000 runnable 
JNI global references: 2087

Любые идеи, что я делаю неправильно здесь?


  • Я не уверен, что происходит, но если зависание длится достаточно долго, вы можете попробовать запустить jstack, когда он заморожен, чтобы увидеть, какие потоки выполняются в данный момент — это должно дать вам подсказку о том, в чем проблема. 09.09.2013
  • Ну, скорее, некоторые JPanels, содержащие компоненты из приведенного выше кода, становятся полностью белыми, поэтому все приложение не зависает, но JPanels становится белым. 09.09.2013
  • Покажите нам, как вы запускаете поток ListenFromServer. Любая синхронизация где-нибудь? Кстати. Предложение Ишавита очень хорошее. 09.09.2013
  • Да, я знаю, что ты имеешь в виду. Если вы выполните jstack <pid>, он покажет вам текущие выполняемые потоки, и есть большая вероятность, что один из них будет EDT, делающим что-то медленное. 09.09.2013
  • @ davida.смотрите мое редактирование :) 09.09.2013
  • @yshavit мне нужно погуглить, как использовать jstack <pid> я не пользовался этим раньше, дай мне секунду 09.09.2013
  • См. мою правку 3 для jstack <pid 09.09.2013
  • Что происходило, пока панели были заморожены/белы? Не похоже, что там происходит что-то особенное — в частности, не похоже, что какой-либо из ваших кодов работает, кроме Thread.sleep в Client.SystemIdleThread. 09.09.2013

Ответы:


1

Что вы делаете, так это то, что вы загружаете тяжелые вещи из сети в один поток, а затем создаете новый поток (потоки) для обновления пользовательского интерфейса, когда что-то происходит. Поскольку пользовательский интерфейс может обновляться только одним потоком за раз, это не то, что вам нужно. Поместите свою сетевую обработку в рабочий поток, и когда оттуда произойдет что-то, относящееся к пользовательскому интерфейсу, инициируйте вызов основного потока пользовательского интерфейса, чтобы что-то обновить.

Взгляните на информацию на этом сайте в целом: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/

Оттуда вам будет интересно использовать рабочий поток для вашей сетевой связи. Затем он будет использовать метод публикации для обновления своих промежуточных результатов.

09.09.2013
  • Итак, я бы поместил свой ListenFromServer в рабочий поток и из этого рабочего потока вызвал бы мои две функции? 09.09.2013
  • @Alosyius да, но из рабочего потока вызовите функцию публикации. Затем переопределите SwingWorker.process, чтобы получить эти результаты, когда они будут опубликованы, и выполните соответствующие действия с вашим пользовательским интерфейсом (например, вызов ваших функций). В ссылке есть (намного упрощенный) пример. 09.09.2013
  • Обратите внимание, что я вполне понимаю, что вы имеете в виду, не могли бы вы написать быстрый пример из моего предоставленного кода? 09.09.2013
  • @Alosyius, если бы вы предоставили полностью работающую ссылку на приложение на github или что-то в этом роде, тогда, возможно, но нет, я не буду начинать кодировать приложение с нуля только для демонстрации. простите :) 09.09.2013
  • @Alosyius Я сделал упрощенный пример подключения к сети фонового рабочего процесса и обновлений пользовательского интерфейса на основе примера Oracle здесь. Может быть, вам будет полезно проиллюстрировать то, о чем я говорю. 09.09.2013
  • Есть также несколько полезных заметок на странице javadoc SwingWorker< /а>. 09.09.2013

  • 2

    Вы выполняете задачу, которая занимает много времени в потоке Swing. Попробуйте профилировать свой код (просто вставьте несколько операторов sysout), чтобы выяснить, где происходит задержка. Обновляйте компоненты GUI только в потоке Swing, не выполняйте в нем никакой обработки/ввода-выводов.

    09.09.2013
    Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..