What’s wrong with that code?

Asked

Viewed 92 times

6

My college professor gave us this code and was asked what’s wrong:

public class Teste {
    private static Teste INSTANCE = null;

    public static Teste getInstance()
    {
        if ( INSTANCE == null )
        {
            INSTANCE = new Teste();
        }
        return INSTANCE;
    }

    private Teste() {
    }
}

I came to the conclusion that:

  1. Test will never be created.
  2. getInstance will return "Garbage".
  3. As the builder is private he will never be called.
  4. More than one test instance can be created

Would that be?

  • Como o construtor está privado ele nunca será chamado. this conclusion is not correct, if the constructor is private, it is only accessible within the class itself.

  • 6

    Your 4 conclusions are wrong.

  • 3
    1. Identation outside Java :D. 2. Singleton is considered by many to be a anti-pattern 3. Most likely what your teacher is looking for: This version is not Thread-safe and may end up creating different instances of Teste in a competing environment. My question on Soen (in English) discusses some of the classic solutions for Concurrent Lazy-loading: https://stackoverflow.com/q/6189099/664577
  • 2

    The biggest problem there is the question asked. The code does not fear anything wrong. If in addition to the code the teacher had passed that it would run in a situation that could be created concurrently and what is the problem of design of this code, then you could answer it better. When the question is bad, the answer gets complicated. That is why it is common for programmers to suffer to create solutions, before solving need to know well what the problem is, need to ask the right question. (I am not talking about this question put here, which is good for a beginner, despite the wrong conclusions)

  • Considering the answer you accepted, read this: https://www.cs.umd.edu/~Pugh/java/memoryModel/Doublecheckedlocking.html

1 answer

6


The problem with the code is that if there is more than one concurrent call on first access to the method getInstance() it can create two Test instances.

The basic solution for this is to synchronize the method:

public static synchronized Teste getInstance()
{
    if ( INSTANCE == null )
    {
        INSTANCE = new Teste();
    }
    return INSTANCE;
}

The problem with this approach is that all calls will be blocked, slowing the overall execution of the program. Imagine such a method on an application server with multiple users accessing the system? Terrible.

A better solution would be a block synchronized within the IF:

public static Teste getInstance()
{
    if ( INSTANCE == null ) {
      synchronized (Teste.class) {
        INSTANCE = new Teste();
      }
    }
    return INSTANCE;
}

This solves the problem of synchronization in all accesses, but it is a "naive" solution, because we actually returned to the initial problem. Like the IF is not synchronized, two threads can enter the IF at the same time and even with synchronization, they will return different instances when INSTANCE for null.

So the most "pure" solution for Singleton Pattern would be to add a double check, thus:

public static Teste getInstance()
{
    if ( INSTANCE == null ) {
      synchronized (Teste.class) {
        if ( INSTANCE == null ) {
          INSTANCE = new Teste();
        }
      }
    }
    return INSTANCE;
}

With this last approach, we guarantee that there will be no loss of performance because of unnecessary synchronization of the entire method.

In addition, we ensure that even if two competing calls to the method come within the first IF, then we have a new synchronized check that guarantees a single Test instance.

So in the worst case, if there are two or more competing calls on first access to getInstance (when INSTANCE is still null), only these first calls will be synchronized, and after the first assignment of INSTANCE, no subsequent call will be synchronized.

A full read on this you find on

Head First Design Patterns.

I recommend you research on Singleton

Note: the constructor private prevents any other class from inadvertently or arbitrarily creating an unwanted Test instance.

  • 1

    Thank you for the reply, I managed to understand the question.

  • 3

    Unless something has changed in Java 8 / 9, without the use of volatile you can face even problems with the two ifs and the block Synchronized (for more details see: https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_java), I myself have suffered from a partially initialized object in the past. An alternative is the following language: https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom

  • It would not be the case to use addiction injection then?

  • -1 for recommending Double-Checked Locking broken: Read this: https://www.cs.umd.edu/~Pugh/java/memoryModel/Doublecheckedlocking.html

Browser other questions tagged

You are not signed in. Login or sign up in order to post.