Strange code behavior for testing a thread-safe singleton

I am new to Java multithreading. Since I need a thread-safe singleton (which I implemented as an enumeration), I wrote a little test code that produces strange output.

Code:

public enum EnumSingleton {
    INSTANCE;


    /** state variables */
    private String message;

    /** Constructor */
    private EnumSingleton() {
    }

    /** add well-known accessor for the instance  (is NOT necessary) */
    public static EnumSingleton getInstance() {
        return INSTANCE;
    }


    /** Accessors */
    public String getMessage() {
        return message;
    }

    public void setMessage(String name) {
        this.message = name;
    }
}

public class App {

    public static void main(String[] args) {

        for (int i = 0; i < 10; i++) {
            final int b = i;
            Thread thread = new Thread("Thread #" + b) {
                @Override
                public void run() {
                    EnumSingleton singleton = EnumSingleton.getInstance();
                    singleton.setMessage("Message written by "+this.getName());
                    System.out.println("Current thread "+this.getName() + ": "+singleton.getMessage());
                }
            };
            thread.start();
        }
    }
}

Thus, each thread writes its name to the enumeration "message" property, which is then printed in STDOUT. I get the following output, which I find strange:

Current thread Thread #6: Message written by Thread #3
Current thread Thread #1: Message written by Thread #1
Current thread Thread #8: Message written by Thread #8
Current thread Thread #5: Message written by Thread #1
Current thread Thread #4: Message written by Thread #4
Current thread Thread #9: Message written by Thread #9
Current thread Thread #7: Message written by Thread #3
Current thread Thread #2: Message written by Thread #3
Current thread Thread #0: Message written by Thread #3
Current thread Thread #3: Message written by Thread #3

I expected that I get a message for each loop counter (0-9). But in this example, I have several posts written by Thread # 3, how can this be? Is there a racial condition?

If my code is crappy: how to check my singleton for thread safety?

+4
4

, message Singleton . , .

enum , , - .

, , - message thread local synchronized, , .

+6

- , message.

volatile . , , - , Message written by Thread #i i.

+5

:

  • № 7 singleton.setMessage("Message written by #7");
  • № 2 singleton.setMessage("Message written by #2");
  • № 0 singleton.setMessage("Message written by #0");
  • № 3 singleton.setMessage("Message written by #3");
  • № 7 System.out.println("Current thread "+this.getName() + ": "+singleton.getMessage())
  • № 2 System.out.println("Current thread "+this.getName() + ": "+singleton.getMessage())
  • № 0 System.out.println("Current thread "+this.getName() + ": "+singleton.getMessage())
  • № 3 System.out.println("Current thread "+this.getName() + ": "+singleton.getMessage())
+4

. , , /. singleton, , , .

, EnumSingleton.

- :

private static final Object lock = new Object();

public static void main(String[] args) {

    for (int i = 0; i < 10; i++) {
        final int b = i;
        Thread thread = new Thread("Thread #" + b) {
            @Override
            public void run() {
                synchronized (lock) {
                     EnumSingleton singleton = EnumSingleton.getInstance();
                     singleton.setMessage("Message written by "+this.getName());
                     System.out.println("Current thread "+this.getName() + ": "+singleton.getMessage());
                }

            }
        };
        thread.start();
    }
}

The whole purpose of the lock object above is to do the install operation and receive the message using the Atomic operation. You cannot leave just by creating methods setMessage()and getMessage().

+2
source

Source: https://habr.com/ru/post/1618447/


All Articles