1

Folks- I have a helper class, the task of which is to build some messages based on the parameters. The class by itself does not have any private data (other than the instance ofcourse).

public class RequestBuilder {
    private static RequestBuilder instance = new RequestBuilder();

    private RequestBuilder() {}

    public static RequestBuilder getInstance() {
        return instance;
    }

    public SetRequest buildSetRequest(Path prefix,
                                      Path path,
                                      ConfigEntity configEntity,
                                      Any protoAnyData) {
        .....
        .....
        return setRequest;
    }

    public GetRequest buildGetRequest(Path prefix,
                                      Path Path,
                                      RetrieveRequestEntity retrieveRequestEntity,
                                      Encoding encoding) {
        .....
        .....
        return getRequest;
    }
}

I understand singleton classes are not multithreading friendly. In this case, what happens when 2 threads try to execute buildSetRequest() at the same time?

Thanks for your time.

EDIT: Based on my need, and as suggested by @BoristheSpide in the comments below, I'm going to make this class as a utility class with the following changes: 1. Make it final. 2. Make methods static. 3. Remove all singleton references.

public final class RequestBuilder {

    private RequestBuilder() {}

    public static SetRequest buildSetRequest(Path prefix,
                                      Path path,
                                      ConfigEntity configEntity,
                                      Any protoAnyData) {
        .....
        .....
        return setRequest;
    }

    public static GetRequest buildGetRequest(Path prefix,
                                      Path Path,
                                      RetrieveRequestEntity retrieveRequestEntity,
                                      Encoding encoding) {
        .....
        .....
        return getRequest;
    }
}

I'm leaving the original code as is, because it is still valid and gives context to the comments and answers to this question.

4
  • 3
    If there is no shared state - i.e. no fields - then it's fine. Commented Feb 28, 2019 at 19:30
  • 1
    ... although that does beg the question of why you need a singleton at all. Just make it a utility class and be done with it. Commented Feb 28, 2019 at 19:41
  • Well what does buildSetRequest exactly? If that call modifies the configEntity argument; and the two calling threads are using the same ConfigEntity instance.. Then you can have problems (since you have shared mutable state) Commented Feb 28, 2019 at 21:07
  • @Daniele, no, none of the input is modified. Commented Feb 28, 2019 at 22:26

1 Answer 1

1

In this case, not too much, because your constructor is empty (what others mention as no shared state). Problems start when you have multiple private instance variables that you have to initialize. In that case, you need some protection like the doble-check:

private static volatile RequestBuilder instance;

private RequestBuilder() {}

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

The reason is that a thread can be suspended at any time. If the current thread constructing the instance is suspended, and another one comes, there can be half initialized instance variables and the object can end up in a corrupted state.

EDIT: About buildSetRequest()

The code is inside a method, if this method create it's own instances itself or works with thread safe classes, there won't be any problem.

Sign up to request clarification or add additional context in comments.

9 Comments

This is just the difference between lazy or eager initialisation. Please read the rules around class initialisers - the code the OP has is perfectly safe from a construction standpoint.
@BoristheSpider Thanks for the negative vote. Yes, but the OP mixes the fact that's a singleton class with the call to buildSetRequest() and I didn't know how to focus the answer. Thanks for your feedback and feel free to expand my explanation.
Sorry, this is not about the focus of your answer. This is about the entire first part of your answer being incorrect. There is no way, given the Java language specification, that a half initialised instance can leak. Your suggestion adds spurious complexity to spurious "facts" about concurrency.
@BoristheSpider Whatever, but what I answered is the correct way to go. Check this and you will see that, effectively, Java memory model allows the publication of partially initialized objects: https://stackoverflow.com/questions/45857765/partial-constructed-objects-in-the-java-memory-model. Again, you can always answer the OP's question too.
That's a completely different example. You are suggesting that a class initialiser is not protected by the JVM. The constructor call is protected by the class initialiser. I don't know what more to say - this answer is fundamentally incorrect and spreads dangerous misinformation about how Java works. I ask you as a professional to delete it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.