Shubhashish
Shubhashish

Reputation: 91

Multithreading behaviour with Static Members

How multithreading behaves in case of static members? Like in case of Singleton Class, if I try to create instance in a static block and in the static method, I return the instance and two threads try to execute getInstance() at the same time..how will this behave internally as static are loaded only one time

public class SingleTonUsingStaticInitialization {

    private static SingleTonUsingStaticInitialization INSTANCE = null;

    static {
        try {
            INSTANCE = new SingleTonUsingStaticInitialization();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private SingleTonUsingStaticInitialization() {
    }

    public static SingleTonUsingStaticInitialization getInstance() {
        return INSTANCE;
    }
}

Upvotes: 3

Views: 112

Answers (3)

Eugene
Eugene

Reputation: 120848

You are safe, in the sense that getInstance will return the same instance to multiple threads. This is guaranteed by The JLS, which is the only place you should delegate your understanding to. Specifically, that chapter says:

For each class or interface C, there is a unique initialization lock LC

And goes on further to say that:

The procedure for initializing C is then as follows:

Synchronize on the initialization lock, LC, for C. This involves waiting until the current thread can acquire LC

In plain english, only a single thread can initialize that static field. Period.

The release of that lock gives proper happens-before guarantees between the action in the static block and any thread that uses that static field. This is implied from the same chapter, from:

An implementation may optimize this procedure by eliding the lock acquisition in step 1 (and release in step 4/5) when it can determine that the initialization of the class has already completed, provided that, in terms of the memory model, all happens-before orderings that would exist if the lock were acquired, still exist when the optimization is performed

Or, again, in plain english, whatever happens in that static block will be visible to all reading threads.


To that end, you will have a proper tool to remove that static block, via a so called "constant dynamic". The infrastructure for it is already in place, but javac still does not use it. You can read more here about it. Some projects already use that - if you have the proper jdk, for example jacoco does it.

Upvotes: 1

rzwitserloot
rzwitserloot

Reputation: 102795

This specific example?

Threadingwise it's fine. Style wise it's deplorable. Do NOT write catch blocks like that. It also means if an exception does occur (it can't here - your constructor is empty), your code will dump half of the info to system error, and then continue, with a null reference instance of an instance of Singleton - causing other code to spit out NullPointerExceptions (because code just keeps going, as you caught the exception instead of letting it happen). If you treat all exceptions in this fashion, a single error will cause hundreds of errors in your logs, all irrelevant except the first one.

Once you take care of this exception handling issue, you can make the variable final, and no longer assign null to it. While you're at it, make the whole class final. It effectively is already (as you only have a private constructor):

public final class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Single() {}

    public static Singleton getInstance() {
        return INSTANCE;
}

The reason this works out when 2 threads simultaneously invoke getInstance, is the classloader mechanism itself: The Classloader guarantees that any given class is never loaded more than once by the same loader, even if 2 threads would simultaneously require this (the classloader will synchronize/lock to avoid this situation), and the initialization process (the static block - which was needlessly convoluted, as the example above shows) is similarly guarded and cannot possibly occur twice.

That's the only freebie you get: For static methods as a general rule, all threads can just run the same method all simultaneously if they want to. And here they do - it's just that the initialization (which includes the ... = new Singleton(); part) is gated to occur only once.

NB: If you must do more complex things, make helper methods:

public final class Singleton {
    private static Singleton INSTANCE = create();

    private Singleton(Data d) {
        // do stuff with 'd'
    }

    private static Singleton create() {
        Data d;
        try {
            d = readStuffFromDataIncludedInMyJar();
        } catch (IOException e) {
            throw new Error("states.txt is corrupted", e);
        }
        return new Singleton(d);
    }
}

This:

  1. Keeps code simple - static initializers are a thing, but fairly exotic java.
  2. Makes your code easier to test.
  3. It's an internal file; if that is missing/broken, that's about as likely / as problematic as one of your class files having gone for a walk. An Error is warranted here. This cannot possibly occur unless you wrote a bug or messed up a build, and hard crashing with a clear exception telling you precisely what's wrong is exactly what you want to happen in that case, not for code to blindly continue in a state where half of your app is overwritten with gobbledygook due to a disk drive crash or what not. Best to just conclude everything's borked, say so, and stop running.

Upvotes: 1

Basil Bourque
Basil Bourque

Reputation: 338171

See the fine points made in the Answer by rzwitserloot.

Here is similar code to the code seen there, but adapted to use an enum as your singleton. Many folks recommended an enum as the ideal way to define a singleton in Java.

Thread-safety is guaranteed because of the same class loader behavior discussed in the other Answer. The enum is loaded once, and only once, per class loader when the class first loads.

If you have multiple threads accessing the single object defined by this enum, the first thread to reach the point where this class is loaded will cause our enum object to be instantiated with its constructor method running. The other remaining threads will block on their attempt to access the enum object until the enum class finishes loading and its one and only named enum object finishes its construction. The JVM juggles all this contention automatically, with no further coding needed by us. All that behavior is guaranteed by the Java specifications.

package org.vaadin.example;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public enum AppContext
{
    INSTANCE;

    private String wording;

    AppContext ( )
    {
        try
        {
            readStuffFromDataIncludedInMyJar();
        }
        catch ( IOException e )
        {
            throw new Error( "Failed to load from text file. Message # 7a608ddf-8c5f-4f77-a9c9-5ab852fde5b1." , e );
        }
    }

    private void readStuffFromDataIncludedInMyJar ( ) throws IOException
    {
        Path path = Paths.get( "/Users/basilbourque/example.txt" );
        String read = Files.readAllLines( path ).get( 0 );
        this.wording = read;
        System.out.println( "read = " + read );
    }

    public static void main ( String[] args )
    {
        System.out.println( AppContext.INSTANCE.toString() );
    }
}

When run.

read = Wazzup?
INSTANCE

Upvotes: 0

Related Questions