But more on that in a moment. First, I'll address reader feedback from last month's column.
Half a dozen readers wrote in to inform me that the following block of code (which relates to the GlobalValues tool we discussed two columns back) is a performance bottleneck for multithreaded access.
public static synchronized GlobalValues getRef() {
if( self == null )
self = new GlobalValues();
return self;
}
Synchronization is only necessary for the part of the method that instantiates a new instance of the GlobalValues. This will happen the first time the method is called. The block of code should therefore only synchronize if it needs to
perform instantiation, as follows:
public static GlobalValues instance() {
if( self == null ) {
synchronized( GlobalValues.class ) {
if( self == null ) {
self = new GlobalValues();
}
}
}
return self;
}
And that's it. No other problems came to my attention this month. (Whew!) On to this month's topic.
Caching is a time-honored method for improving the performance of an application. Instead of constantly creating and destroying objects as needed, a cache holds on to them and reuses them when appropriate. The Web browser you're running right now uses caching in a number of ways. For example, the JavaWorld logo at the top of this page appears at the top of all the articles. But your browser doesn't reload the image as you travel from one article to the next. The browser caches the image and reuses it when needed.
However, the browser can't cache the image forever. The more sites you visit, the more images the browser saves, and soon you run out of hard drive space. So, the caching mechanism in your browser has to perform some garbage collection. The browser basically sets a maximum space limit for caching images and destroys the oldest images in the cache when that limit is reached.
In Java, it's incredibly simple to implement a crude caching mechanism using the Hashtable class. Here's how: When you (or your application) need an object, first check to see if it's in the Hashtable. If the required object isn't there, create a new instance of it and put it into the Hashtable. This way, the next time you need it, it's right where you left it.
The tricky part is the cleanup. At some point, your application needs to go through the Hashtable and clean up the objects that haven't been used for a while and are wasting memory. Where do you put this cleanup code? How
often do you call it? These are problematic issues, but what if you had a special instance of the Hashtable that knew how to clean itself up? Hello Cachetable!
The magic behind the Cachetable is a timer thread that periodically reminds the table to clean itself up. I've dubbed this tool Ping. In the olden days of submarine warfare, when a sub was looking for a target it would send out an audible ping sound. This sound would then bounce back from any obstruction, thus revealing the position of the target. In the wonderful
land of Unix and the Internet, there exists a little utility called ping that is used to the same effect. The Unix utility sends out a packet to its "target" machine and if the target machine is
up and running it "bounces" the packet back.
ping utility
Double-Checked Locking is BrokenBy Anonymous on October 28, 2008, 6:09 amI know this is an old article but people could still read it and be misguided. Check out http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Reply | Read entire comment
View all comments