Java单例类和多线程

时间:2019-02-28 19:18:50

标签: java multithreading singleton

民谣- 我有一个帮助器类,其任务是根据参数构建一些消息。该类本身没有任何私有数据(课程实例除外)。

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;
    }
}

我知道单例类不是多线程友好的。在这种情况下,当两个线程尝试同时执行buildSetRequest()时会发生什么?

感谢您的时间。

编辑: 根据我的需要,并按照@BoristheSpide在以下注释中的建议,我将使该类成为实用程序类,并进行以下更改: 1.使其最终。 2.使方法静态。 3.删除所有单例引用。

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;
    }
}

我将保留原始代码,因为它仍然有效,并且为注释和对该问题的答案提供了上下文。

1 个答案:

答案 0 :(得分:0)

在这种情况下,不要太多,因为您的构造函数为空(其他人称为没有共享状态)。当您有多个必须初始化的私有实例变量时,问题就开始了。在这种情况下,您需要一些保护,例如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;
}

原因是可以随时挂起线程。如果构造实例的当前线程被挂起,而另一个线程挂起,则可能有一半的实例变量已初始化,并且该对象最终可能处于损坏状态。

编辑:关于buildSetRequest()

代码位于方法内部,如果该方法本身创建了自己的实例或与线程安全类一起使用,则不会有任何问题。