You are here

Java advanced topic, shortcomings, troubles, tricks

Here is a list of issues I came across when working with Java. I have strong C/C++ and Windows OS background, so some of the issues maybe biased.

Atomic operations, synchronize and volatile

The language guarantees that reading or writing a single variable is atomic unless the variable is of type long or double ... While the atomicity guarantee ensures that a thread will not see a random value when reading atomic data, it does not guarantee that a value written by one thread will be visible to another (Bloch, Effective Java, Item 48).

The synchronized and volatile has quite different effects on code:

  • synchronize guaranties, that onle one thread can enter a block of code. But it doesn't guarantee, that variables modifications done within synchronized section will be visible to other threads. Only the threads that enters the synchronized block is guarantieed to see the changes. This is the reason why double checked locking is broken - it is not synchronized on reader's side. Reading thread may see, that singleton is not null, but singleton data may not be fully initialized (visible). Enter to synchronize block is read barrier and leave of synchronize block is write barrier. In the case on readers/writers volatile provides finer control over read/write barriers.
  • volatile read is read barrier and volatile write is write barrier, for instance write to volatile singleton static field guaranties that writes to the singleton object will be finished before the write to volatilie static field. However it doesn't prevent creation singleton of two objects, this is provided by synchronize
  • Class final static fields doesn't need to be volatile, JVM takes care of this problem. So preferrred code for lazy singleton initialization is singleton holder:
    public class Singleton {
    private static class SingletonHolder {
    private final static Singleton singleton = new Singleton();
    }
    
    public static Singleton getSingleton() {
    return SingletonHolder.singleton;
    }	
    
    private Singleton() {
    ...
    }
    ...
    }
  • The reordering of memory writes also depends on HW. For instance multi-code x86 platform has quite conservative memory model, you wan't see any memory reordering. In other words, the double checked locking problem will not occur on x86.
  • The java.util.concurrent.atomic has a small toolkit of classes that support lock-free thread-safe programming on single variables.

Thread fairness vers. throughput

Java thread scheduling is not fair. It is not difficult to create so many working threads

serialVersionUID

If you do not specify the identification number explicitly by declaring a private static final long field named serialVersionUID, the system automatically generates it by applying a complex deterministic procedure to the class. The automatically generated value is affected by the class's name, the names of the interfaces it implements, and all of its public and protected members. If you change any of these things in any way, for example, by adding a trivial convenience method, the automatically generated serial version UID changes. If you fail to declare an explicit serial version UID, compatibility will be broken. (Bloch, Effective Java, Item 54)

Get version of jar package

If the jar version information is not part of the jar name or it is not written in META-INF/MANIFEST.MF, it is not easy to get it. You can use Google, MD5 checksum and Maven repository. Make MD5 checksum of the jar (you can use md5sum or its windows port) and then search it in Google prepending site:www.ibiblio.org to the query.

Process separation

I was not clear to me how JBoss Application Server can run the web server and JavaEE container in the same JVM and how the memory used by the processes is separated. Here are link that explains the magic:

Dynamic proxy API

Dynamic Proxy Classes and Explore Dynamic Proxy API. Dynamic proxy API can be used for various purposes, for instance access control proxy, facade proxy, remote proxy, methods interposing.

Class methods interposing

Using java.lang.reflect.Proxy to Interpose on Java Class Methods. There is a United States Patent 7093242 on Dynamic class interposition

Process priority

There is no support for setting process priority for processes started through Runtime.Exec() or ProcessBuilder. Each OS manages priorities in different way, some OS don't have priorities at all. Jakarta commons-exec seems to use the methods mentioned above.

Using JConsole to Monitor Applications

The Java 2 Platform, Standard Edition (J2SE) 5.0 release provides comprehensive monitoring and management support. You can observe information about an application running on the Java platform. Look at jconsole.

Java final keyword and true constant instances

Final instances

Unfortunately Java doesn't have true constant instances. The final keyword can be applied to primitive types and to a reference type. But final on reference type means, that the reference will not change, the referenced object may change!

If you want to have constant object, or something similar to constant object, you can:

  • declare all members of the class private or protected
  • define an Interface with similar name that ONLY defines those methods that don't changes the "contents" of an instance
  • tell your original class to implement this interface
  • use the interface instead of the original class for local vars or parameters if you want to have them to be "const"

There are several variants to this pattern, see java final vs. c++ const

Final local variables and function parameters

In C/C++ the const is also used as a documentation tool. When a function or method doesn't modify object passed as parameter, that parameter is marked as const. Because java doesn't use true constants, this is of no use. You can mark parameters as final, but final is not considered part of the method signature.

There are three reasons why to use final on local variables:

  • Compiler optimization, aggressive optimizations in a multithreaded context. See JSR 133
  • Prevent accidental change of the variable
  • Access local variable from anonymous class

For more read The Final Word On the final Keyword.

Java memory mapped files are broken

Because there is no API to unmap a memory mapped file, you cannot reliably delete the file once you mapped it. According to Sun, this bug will not be fixed. See Sun's Bug Database:

You may use the following trick to force unmap with forced garbage collection:

final MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, size);
....
final WeakReference bufferWeakRef = new WeakReference(bb);
bb = null;

final long startTime = System.currentTimeMillis();
while(null != bufferWeakRef.get()) {
if(System.currentTimeMillis() - startTime > 10)
// give up
return;
System.gc();
Thread.yield();
}

Boolean.getBoolean() is probably not what you want to call

Boolean.getBoolean(String) seems like perfect function name when you want to convert from String to boolean primitive. Nope. getBoolean(String) reads system property. Most of the time you want to call Boolean.parseBoolean(String). This shortcut function is source of troubles, it should be deprecated.

Of course the same applies for Integer.getInteger(String), Long.getLong(String).