Synchronized New Object


code-fun java

My favorite “baddest piece of code encountered” is this one:

private static int clusterIdSeed = ...;
// ...
synchronized (new Object()) {
    int rdm = new Random(clusterIdSeed).nextInt();
    clusterId = String.valueOf((rdm<0)?(rdm*(-1)):rdm);
    clusterIdSeed = clusterIdSeed * 7;
}
// clusterId is used

It contains so much strange logic on just a few lines. It starts with:

synchronized (new Object()) {
	// ...
}

The obvious intention is that the code within the block should not be executed concurrently by multiple threads. Why? Perhaps the update of clusterIdSeed = clusterIdSeed * 7 is not atomic. Or Random.nextInt() is supposed to be not thread-safe (it is). In any case multiple threads will happily and concurrently enter the block because each thread will synchronize on a new instance of Object.

“But what about memory barriers?” I hear you calling? “At least synchronized will flush the caches so that other threads can pick up the values. volatile for the poor…” Well… not even that if you read Why is synchronized (new Object()) {} a no-op? on StackOverflow: According to the spec the “happens before” stuff does only apply to the new Object() part - a conforming JVM doesn’t need to flush the whole cache, it could flush only the new object.

The next interesting part:

    int rdm = new Random(clusterIdSeed).nextInt();

This spawns two questions:

Minor nitpick: rdm is a strange name for a Random instance: Most people (including me) would have used rnd as the abbreviation.

The next part:

	clusterId = String.valueOf((rdm<0)?(rdm*(-1)):rdm);

Also two things:

The last part:

	clusterIdSeed = clusterIdSeed * 7;

This line might be reason for the synchronized block. But it is also related to the new Random(clusterIdSeed) line (and its problems). Additionally I think this is a kind of “spillover thinking” with the usual recommendation to use primes when implementing hashCode(). See StackOverflow: Why use a prime number in hashCode?

OK… OK… I would have written the line more concisely like this – if I’m forced to do so:

	clusterIdSeed *= 7;

but that is – after all – really a minor thing.

Wrapping it up – what is a better and clearer solution? This code:

private static Random rnd = new Random();
// ...
clusterId = Integer.toString(Math.abs(rnd.nextInt()));