Java Specialist Master Course Field Report

Last week I had the pleasure attended Heinz Kabutz Java Specialists Master course to sharpen my Java skills. Java Champion Heinz, is a great trainer who manages to combine anecdotes, hard facts and deep Java knowledge with engaging exercises to a well done course. The scope was the whole spectrum of Java, but focusing on the details you normally do not use, or know how to use. Some of the material he already published as part of his newsletters, which are read all around the world.

Let me share my impressions on the course with you in this day by day review…

Day 1

The course started with discussing Threads, and how we should use them. Quite a complex topic for early morning. We played with a ThreadGroup that became a custom Thread pool. ThreadGroup is not the best designed class. Heinz called it a child’s drawing from the early years of Java. I found using the java.util.concurrent Locks really easy. Finally gone are the days of synchronized(). Before the lunch break, Heinz showed us his laws on concurrency, which he also presented in an abbreviated form at our meet the experts – performance event. We came across this code:

private boolean running = true;
public void dojob() {
  while(running) {
    // do something useful
 }
}
public void shutdown() {
  running = false;
}

When running in a Server VM (with java -server), this might never stop, due to optimizing running would be inlined by HotSpot with being true all the time. To avoid this you would have to make it volatile. Because I asked about debugging, we tried stopping there and the debugger showed us: running = false. Still the code continued to executed, because the debugger sees the correct field value, but the running code doesn’t. It gets more interesting with this code:

public void doJob() {
  boolean myRunning = running;
  while(running){
    // do something useful
    myRunning = running;
  }
}

When looking with the debugger we saw this:

running = false; myrunning = true;

however the loop still looped. But when forcing the line to execute via F7, code terminated. This can be a nightmare to debug, so it is good to know what you should take care of when writing multithreaded programs.

Also something to remember is to check

if (Thread.interrupted()) {
  throw new InterruptedException()
}

as first code in all methods declaring an InterruptedException.

We learned about CompletionService looks like an interesting interface for mass processing of asynchronous work. So, who needs closures? :-)

Day 2

We started with Java new (yet another new?) IO, which brings quite a lot of new features, but somehow is not as widely used as it should be. One reason might be that it can easily get much more complicated to use. Perhaps one should try easy examples before writing an Async nonblocking server (which you can after attending the course :-)).

FileChannel fc = new RandomAccessFile("test.txt", "r").getChannel();
MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());

Second half was on understanding Java memory management. This of course is less often really applicable, but understanding it is quite critical to solving problems. We had a look at stuff like caching and pooling, and why this creates leaks or loitering objects. This reminds me of my older post about tag pooling in servlet containers. I never understood really why tags are pooled, and even worse, do not have proper lifecycle methods to detect this when using an IDE. We used jVisualVm and HPjMeter to watch the GC at work.

Day 3

On day 3, I learned some interesting inner mechanics of Collection classes I did not use before (like PriorityQueue), as well as some nasty tricks on classloading. Heinz explained java.lang.reflect.Proxies really well, and once understood, using them was not that difficult. Actually the best instruction is in the JavaDoc, but you must know how to read it:

Foo f = (Foo) Proxy.newProxyInstance(
		Foo.class.getClassLoader(), new Class[] { Foo.class },
		new InvocationHandler() {
		  public Object invoke(Object foo, Method method, Object[] arguments) throws Throwable {
		    return method.invoke(foo, arguments);
		  }
		});

In the afternoon we discussed about Exceptions, and I made up my mind on checked vs unchecked exceptions. Personally I will use unchecked exceptions for developer/programming errors. Catching them is not required, app may crash – Developers should fix this. However everything which is related to the Environment the app runs ins should work with checked exceptions. Ideally they provide sensible information, not just a message. Also quite important: Just rethrow Exceptions! Found yourself not able to decide what to do with an InterruptedException? Well just rethrow it :-) And handle it in the Thread code (calling interrupted() and exiting a loop). I never did that often, because I don’t like polluting my method signature, but it should be considered. Do not be afraid of retrowing Exceptions.

Day 4

The last day of the course started with a tough performance optimization exercise. The tough part was that we were not allowed to improve the code until we had all the numbers written down and eliminated any overhead of testing code. I especially liked this, because it thought me how eager I am sometimes fixing issues that I forget proving them first. As kind of side note, we discussed the various modes the JVM can run in and found out how slow java -Xint is. After having sped up the code down to 10% of its initial runtime, we moved on to Date and Time, which was a bit short chapter. I can recommend using jodatime and icu4j, and try to stay away from java.util.Date. Before the end of the course we covered logging including some nifty tricks. The most important lesson about logging is that you need to use code guards (which was not new to me, but I like the term, I never heard before):

if (log.isDebugEnabled()){
  log.debug(complexObject.toString() + expensive.toString());
}

Wrap-Up

I can wholeheartedly recommend this course. 4 days packed with lots of information and exercises that are well done so that they are a challenge for every participant. You should have worked with Java already some time. This is definitely not a beginners course. You will rush past topics which you can only grasp when you have experienced the problem before. I can also recommend taking this training in German, because Heinz has a really funny accent :-)

  • Facebook
  • Delicious
  • Digg
  • StumbleUpon
  • Reddit
  • Blogger
  • LinkedIn
Fabian Lange

5 Responses to Java Specialist Master Course Field Report

  1. I’m not sure that I like the part about log code guards. Is this really *the* most important lesson to learn about logging and performance? IMHO, isDebugEnabled is noise which extremely rarely is justified by the saving the performance hit of .toString.

    What kind of performance benefits did you achieve, and how expensive was this toString?

    Also the checked exceptions.. Saying “everything which is related to the Environment the app runs ins should work with checked exceptions” is too big of a generalization for me. What about data access exceptions and IOExceptions? In many cases you can’t deal with these, so having them checked is more annoying than useful.

    I’m afraid that I meet those two pieces of belief quite often, although most of the really smart developers I know have long since abandoned them with good reasons. I think it’s a bit scary that Kabutz is still spreading these old tricks.

    Mind, that the rest of the course is probably great, it’s just these two points that bother me.

  2. Fabian Lange says:

    Hi Thomas,
    code guards are important. the if is less expensive than String object creation. This is not caught by Escape Analysis (-X:+DoescapeAnalysis) because it creates objects in the String pool. It also creates a method call that needs to copy parameters onto the stack. You can profile it. It is almost always slower than the ugly if.
    You can speed it even more up by using a public static final boolean DEBUG = false;
    this will remove the if + debug line during compilation.

    Regarding Exceptions: Yes they are annoying. But wouldn’t it be better to be able to do a sensible retry? Very often you can’t do a sensible retry, so you end with aborting, or worse, ignoring.

    If being smart means you would have a catch for RuntimeException, I disagree. you should not catch RuntimeExceptions.

    Also note that the Exception decision was my very own. Heinz has a similar but not one that I could repeat in detail. However the code guard is the right thing to use if you care about performance of your logging statements.

  3. Hi Fabian, thanks for your answer.

    To be clear: No, I don’t really care about the performance of the log statements. I think there are so many other places in code I would work on performance (double for-loops with quadratic run time for instance).

    If it was an embedded performance critical application, I would perhaps see the need for it, but as long as you’re in a web application, or anything that touches disk or is distributed, you will not get a practical benefit from this. The already code-noisy log.debug statements will now be 3 lines each instead of just one.

    Regarding exceptions, we may be on separate sides of the checked/unchecked chasm/flamewar subject.

    I know it’s hard to convince people of this, but it’s a bit like the log statements: Good ideas in principle, but in practice, average developers end up surrounding *all* log statements with isDebugEnabled (even when they run with debug enabled in production), and making all exceptions checked because “it’s safer”.

    Keep in mind that checked exceptions is something of an experiment that the developers of Java introduced to try it out. They don’t exist in any other programming language AFAIK.

    The long term effect of having them in the language can be widely discussed, but my opinion (and many others) is that we would be better off without them, as they have been overused, by a myriad of developers as well as the JDK developers. As food for thought, the C# originators chose to leave checked exceptions out of .Net..

    The best thing I can do is to refer to this list of links discussing the subject: http://www.java.no/forum/posts/list/10946.page (Norwegian page but English links).

    I hope you can take the time to look at some of those links, maybe you’ll change your mind about it :)

  4. Mirko says:

    Hi Thomas,

    I’ve seen missing isDebugEnabled(…) Statements as the reason for bad performance in many performance tuning assignments. Especially if one of these three points is true:

    – The methods with the debug-Statement are called very often (I’ve seen this with millions of call per requests)

    – The String that should be logged is “complex” – means that it is concatinated AND dynamic, e.g. logs a lot of parameters/attributes.

    – The object that is logged has a “expensive” toString() method, which is implicitly called – in many cases I’ve profiled this and the developers didn’t even know that the toString() was so expensive, as they used others components/frameworks.

    So yes, isDebugEnabled() is ugly, but in many cases necessary (in others maybe not) – as it can be performance critical I would always advise to set up coding guidelines that include a mandatory isDebugEnabled().

    With regard to the exceptions: There are so many discussions about it that there is no “good” or “bad” in my opinion. The only thing I would suggest is to have a common usage guideline for a whole project.

  5. Nikos says:

    Hi Fabian, very nice post! You are lucky to attend a course of Mr. Kabutz. Thanks for sharing these interesting points.

    Kind Regards,
    Nikos

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>