The Source for Java Technology Collaboration
User: Password:



Bruce Chapman's Blog

Bruce Chapman Bruce Chapman has been developing in Java since 1998, predominantly building telecommunication sytems. He has a degree in mechanical engineering from so long ago that it is almost irrelevant, and lives in New Zealand. Bruce was a member of the JSR269 expert group. His interest is primarily in the SE space but has also worked on ME and EE projects.



List Separators

Posted by brucechapman on March 25, 2008 at 05:58 PM | Permalink | Comments (12)

In his Disturbing Thoughts from a Developing Mind blog, fellow kiwi Mark Derricutt discusses a situation where new for loops don't provide enough power for a particular case. (And yes this blog has been sitting drafted but unpublished for ages :( )

The case in point is building a String from the concatenation of a List of Strings with some separator between them, in this case a semi-colon.

The problem is expressed as "append the separator after each element, except the last one". What seems to have evaded Mark and his commenters is that the problem can be expressed differently.

If you restate the problem as "append the separator before each item except the first one" then you are one step away from what seems to me to be an elegant solution, at least compared to the others offered.

That final step is to realise that "except the first one" can be rephrased as except the first one in which case you prepend nothing".

Applying this to the relevant section of Mark's code yields

StringBuilder sb = new StringBuilder();
String separator = "";
for (String listenerClassName : data.TEST_LISTENERS) {
    if (listenerClassName != null && !"".equals(listenerClassName)) {
        sb.append(separator).append(listenerClassName);
        separator = ";";
    }
}

There is a more OOish solution, which is to have a (tiny) class thus

public Class Separator {
    private String next = "";
    private String separator;
    public Separator(String separator) {
        this.separator = separator;
    }

    public String get() {
        String result = next;
        next = separator;
        return result;
    }
}

which returns an empty string the first time get() is called, then the configured value thereafter.

With this we can code the loop as

StringBuilder sb = new StringBuilder();
Separator sep = new Separator(";");
for (String listenerClassName : data.TEST_LISTENERS) {
    if (listenerClassName != null && !"".equals(listenerClassName)) {
        sb.append(sep.get()).append(listenerClassName);
    }
}

So how do you tackle this problem?



Hot Threads

Posted by brucechapman on March 25, 2008 at 05:02 PM | Permalink | Comments (4)

I'm setting up my new desktop development machine, and netbeans installation is atrociously slow, like several minutes just to display the splash screen. The task manager shows the process consuming 50% CPU (on a dual core). After stuffing around barking up several wrong trees I drag out a JMX based tool I wrote a while back to find hot threads in a running application.

I had previously encountered slow startup with Netbeans 5.5 (itself - not the installer) and based on A. Sundararajan's blog Using Mustang's Attach API I had written a tool to output the stack traces for the three busiest threads in a java process.

Here's the source code. And for those that just need to do the same thing without understanding internals, Download the jar file

The program attaches to the local java process (specified by the PID on the command line), it grabs information about the processing time of all threads, twice 500ms apart, and uses that to find the three busiest threads. It then takes 10 stacktrace snapshots of those three threads at 10ms intervals, and looks for the common parts on those stack traces for each thread. If a thread is busy, normally most of the stack stays the same, and just the top part changes. The program then outputs to common parts of the stack traces. From there you can see which thread is running hot, and where it is.

So I enabled PID display in the Window's task Manager and ran the program. Here's what I saw...

C:\>java -jar C:\projects\experimental\HotThread\dist\HotThread.jar 3544
java.lang.UnsatisfiedLinkError: no attach in java.library.path
Exception in thread "main" com.sun.tools.attach.AttachNotSupportedException: no
        at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:190)
        at hotthread.Main.main(Main.java:52)

That was due to java's installation running the JRE's copy of java.exe, but it doesn't have some of the attach API support files, so you need to run the JDK version of java.exe. Trying again...

C:\>"C:\Program Files\Java\jdk1.6.0_05\bin\java.exe"  -jar C:\projects\experimental\HotThread\dist\HotThread.jar 3544
106.3% CPU Usage by Thread 'Swing-Shell'
  10/10 snapshots sharing following 10 elements
    sun.awt.shell.Win32ShellFolder2.getAttributes0(Native Method)
    sun.awt.shell.Win32ShellFolder2.access$600(Unknown Source)
    sun.awt.shell.Win32ShellFolder2$6.call(Unknown Source)
    sun.awt.shell.Win32ShellFolder2$6.call(Unknown Source)
    java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    java.util.concurrent.FutureTask.run(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    sun.awt.shell.Win32ShellFolderManager2$ComInvoker$3.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)

 1.6% CPU Usage by Thread 'RMI TCP Connection(9)-172.30.41.210'
  10/10 snapshots sharing following 32 elements
    sun.management.ThreadImpl.getThreadInfo0(Native Method)
    sun.management.ThreadImpl.getThreadInfo(Unknown Source)
    sun.reflect.GeneratedMethodAccessor106.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    java.lang.reflect.Method.invoke(Unknown Source)
    com.sun.jmx.mbeanserver.ConvertingMethod.invokeWithOpenReturn(Unknown Source)
    com.sun.jmx.mbeanserver.MXBeanIntrospector.invokeM2(Unknown Source)
    com.sun.jmx.mbeanserver.MXBeanIntrospector.invokeM2(Unknown Source)
    com.sun.jmx.mbeanserver.MBeanIntrospector.invokeM(Unknown Source)
    com.sun.jmx.mbeanserver.PerInterface.invoke(Unknown Source)
    com.sun.jmx.mbeanserver.MBeanSupport.invoke(Unknown Source)
    javax.management.StandardMBean.invoke(Unknown Source)
    com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(Unknown Source)
    com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(Unknown Source)
    javax.management.remote.rmi.RMIConnectionImpl.doOperation(Unknown Source)
    javax.management.remote.rmi.RMIConnectionImpl.access$200(Unknown Source)
    javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(Unknown Source)
    javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(Unknown Source)
    javax.management.remote.rmi.RMIConnectionImpl.invoke(Unknown Source)
    sun.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    java.lang.reflect.Method.invoke(Unknown Source)
    sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    sun.rmi.transport.Transport$1.run(Unknown Source)
    java.security.AccessController.doPrivileged(Native Method)
    sun.rmi.transport.Transport.serviceCall(Unknown Source)
    sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)

 0.0% CPU Usage by Thread 'Reference Handler'
  10/10 snapshots sharing following 3 elements
    java.lang.Object.wait(Native Method)
    java.lang.Object.wait(Object.java:485)
    java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)

So armed with this information, a quick search of the JDK bug database looking for "sun.awt.shell.Win32ShellFolder2" yields Bug ID: 5033747 JFileChooser is very slow on Windows XP but that is about JFileChooser which doesn't seem related to my problem, however the stack trace matches. One of the related bugs is Bug ID: 5050516 JFileChooser very slow in XP if directory contains large zip files and a light turns on. I have some big zip files on my desktop temporarily while I set things up. In that bug it shows how to disable XP's feature of treating zip files as directories which seems like it might be the root cause.

So I disabled XP's horrible ZIP file handling (which would be marvellous if it wasn't so pathetically slow), and ... Drum roll ... netbeans was installed in a couple of minutes.

Thank you JMX. Maybe a hot thread detector would be useful in jconsole and visualVM.

June 2008
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30          


Search this blog:
  

Categories
Community: OpenJDK
JSR
Programming
Tools
Virtual Machine
Archives

March 2008
February 2008
January 2008
December 2007
November 2007
August 2007

Recent Entries

List Separators

Hot Threads

Announcement - "No Closures" prototype



Powered by
Movable Type 3.01D


 Feed java.net RSS Feeds