2

我有一个基本的小聊天客户端,当 java 客户端从服务器接收到新消息时,我正在从一个线程更新多个 GUI 组件。

这是线程:

  /*
   * 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

有什么想法我在这里做错了吗?

4

2 回答 2

3

您所做的是在一个线程中从网络加载繁重的内容,然后创建一个新线程以在发生某些事情时更新用户界面。由于一次只能由一个线程更新 UI,这不是您想要做的事情。将您的网络处理放在工作线程中,当与 UI 相关的事情从那里发生时,启动对主 UI 线程的调用以更新某些内容。

看一下这个网站的整体信息: http: //docs.oracle.com/javase/tutorial/uiswing/concurrency/

从那里,您将有兴趣使用工作线程进行网络通信。然后它将使用发布方法来更新其中间结果

于 2013-09-09T16:27:24.667 回答
2

您正在 Swing 线程上运行需要很长时间的任务。尝试分析您的代码(只需坚持一些 sysout 语句)以找出延迟发生的位置。只在 Swing 线程中更新 GUI 组件,不要在其中做任何处理/IO。

于 2013-09-09T14:48:03.143 回答