~pperalta

Thoughts on software development and other stuff

JConsole, let me introduce you to SwingWorker

without comments

Today when I was using JConsole I noticed that when I tried to connect to a process the UI was hanging. The application that it was trying to connect to was not in a good state, but I was surprised at the lack of a responsive UI. Curious, I captured a thread dump and saw this gem:

"AWT-EventQueue-0" prio=6 tid=0x0100cd00 nid=0x899e00 runnable [0xb0d13000..0xb0d14d90]
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
        - locked <0x2559e880> (a java.net.SocksSocketImpl)
        at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:432)
        at java.net.Socket.connect(Socket.java:520)
        at java.net.Socket.connect(Socket.java:470)
        at java.net.Socket.(Socket.java:367)
        at java.net.Socket.(Socket.java:180)
        at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:22)
        at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:128)
        at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:569)
        at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:185)
        at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:171)
        at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:306)
        at sun.rmi.transport.DGCImpl_Stub.dirty(Unknown Source)
        at sun.rmi.transport.DGCClient$EndpointEntry.makeDirtyCall(DGCClient.java:328)
        at sun.rmi.transport.DGCClient$EndpointEntry.registerRefs(DGCClient.java:275)
        at sun.rmi.transport.DGCClient.registerRefs(DGCClient.java:112)
        at sun.rmi.transport.LiveRef.read(LiveRef.java:277)
        at sun.rmi.server.UnicastRef2.readExternal(UnicastRef2.java:54)
        at java.rmi.server.RemoteObject.readObject(RemoteObject.java:438)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:946)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1809)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1719)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
        at javax.management.remote.rmi.RMIConnector.findRMIServerJRMP(RMIConnector.java:1871)
        at javax.management.remote.rmi.RMIConnector.findRMIServer(RMIConnector.java:1789)
        at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:259)
        - locked <0x25600378> (a javax.management.remote.rmi.RMIConnector)
        at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:248)
        at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:207)
        at sun.tools.jconsole.ProxyClient.(ProxyClient.java:156)
        at sun.tools.jconsole.ProxyClient.getProxyClient(ProxyClient.java:57)
        at sun.tools.jconsole.ConnectDialog.actionPerformed(ConnectDialog.java:342)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1882)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2202)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
        at java.awt.Component.processMouseEvent(Component.java:5602)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3135)
        at java.awt.Component.processEvent(Component.java:5367)
        at java.awt.Container.processEvent(Container.java:2010)
        at java.awt.Component.dispatchEventImpl(Component.java:4068)
        at java.awt.Container.dispatchEventImpl(Container.java:2068)
        at java.awt.Component.dispatchEvent(Component.java:3903)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4256)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3936)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3866)
        at java.awt.Container.dispatchEventImpl(Container.java:2054)
        at java.awt.Window.dispatchEventImpl(Window.java:1801)
        at java.awt.Component.dispatchEvent(Component.java:3903)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
        at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:180)
        at java.awt.Dialog$1.run(Dialog.java:535)
        at java.awt.Dialog$2.run(Dialog.java:565)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.awt.Dialog.show(Dialog.java:563)
        at java.awt.Component.show(Component.java:1302)
        at java.awt.Component.setVisible(Component.java:1255)
        at sun.tools.jconsole.ConnectDialog.setVisible(ConnectDialog.java:415)
        at sun.tools.jconsole.JConsole.showConnectDialog(JConsole.java:583)
        at sun.tools.jconsole.JConsole.access$100(JConsole.java:34)
        at sun.tools.jconsole.JConsole$4.run(JConsole.java:702)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:461)
        at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:184)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:176)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)

Every Swing programmer that has gotten past Hello World knows that this is a no-no. AWT and Swing components are rendered by a single thread, and if that thread gets blocked then you end up with an unresponsive UI. Clearly there should never be any network code in the stack trace of the AWT event thread. This is on the 1.5 VM on OS X so I don’t know if Sun or Apple is to blame (I assume Sun), but if this isn’t fixed yet in 1.6 then they should review the Swing Tutorial:

Tasks on the event dispatch thread must finish quickly; if they don’t, unhandled events back up and the user interface becomes unresponsive.

Written by Patrick Peralta

February 10th, 2009 at 11:29 pm

Posted in Development