清除 Java 中的单例实例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16506014/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 23:09:50  来源:igfitidea点击:

Clear Singleton instance in Java

javadesign-patternssingleton

提问by Nameless

I have a Singleton class to save the state of an application's module. This class simply have a lot of class variables with setters and getters :

我有一个 Singleton 类来保存应用程序模块的状态。这个类只有很多带有 setter 和 getter 的类变量:

public class ModuleState{

private static ModuleState instance;

private A a;
private B b;
private C c;
..
..
..
..

private ModuleState (){}

public ModuleState getInstance(){
    if(instance==null)
        instance=new ModuleState();

    return instance;
}

}

}

At a precise moment of the application lifecycle, i have the need to CLEAR the module's state. What i do now is to reset ALL the variables in ModuleState by a clearAll() method like this:

在应用程序生命周期的精确时刻,我需要清除模块的状态。我现在要做的是通过像这样的 clearAll() 方法重置 ModuleState 中的所有变量:

public void clearAll(){
    a=null;
    b=null;
    c=null;

    ..
    ..
}

My question is the following : there is a cleaner method to do this reset? Possibly clearing the singleton instance itself, without resetting every class variable?

我的问题如下:有更清洁的方法来进行此重置吗?可能清除单例实例本身,而不重置每个类变量?

The problem with this approach is that i may have the need to add a new class variable to the ModuleState. In this case i must remember to add a line in the clearAll() method to reset the new variable.

这种方法的问题是我可能需要向 ModuleState 添加一个新的类变量。在这种情况下,我必须记住在 clearAll() 方法中添加一行以重置新变量。

回答by Trinimon

What about ...

关于什么 ...

public static volatile ModuleState instance = null;

public static void reset() {
    instance = new ModuleState();
}

p.s.: as per discussion below: in a multithreaded environment it's very important to synchronize the access on the instance because the JVM is allowed to cacheits value. You can use volatileas shown above. Thanks to all!

ps:根据下面的讨论:在多线程环境中,同步对实例的访问非常重要,因为允许 JVM缓存其值。您可以使用volatile如上图所示。谢谢大家!

Cheers!

干杯!

回答by radai

no, this approach is perfectly acceptable. you are of course synchronizing access to these state objects in some way, right? otherwise you risk someone seeing a half-cleared config object.

不,这种方法是完全可以接受的。您当然是以某种方式同步对这些状态对象的访问,对吗?否则,您可能会冒着看到半清除配置对象的风险。

another thing you could do to future-proof yourself against any extra state added in the future is store all of your state in a HashMap, for example, instead of individual fields. this way, clear()ing the hashmap ensures that all state is wiped and adding any extra state in the future becomes safer

例如,您可以做的另一件事是将您的所有状态存储在 HashMap 中,而不是单个字段,以防止将来添加任何额外的状态。这样,清除()哈希图可确保清除所有状态,并且将来添加任何额外状态变得更安全

回答by christopher

You need to maintain the same object instance, in order to comply with the Singleton pattern, so your approach makes sense: altering the members.

您需要维护相同的对象实例,以符合单例模式,因此您的方法很有意义:更改成员。

However, if you wanted to clean it up a little bit, why not just have an internal list, like:

但是,如果您想稍微清理一下,为什么不拥有一个内部列表,例如:

 ArrayList<Object> members = new ArrayList<Object>();
 // If it actually is Object, there's no need to paramaterize.
 // If you want, you can actually make the members implement a common interface,
 // and parameterize the ArrayList to that.

Another Option would be to have a HashMap, that binds the key word to the member.

另一种选择是使用HashMap, 将关键字绑定到成员。

 HashMap<String,Object> members = new HashMap<String,Object>();
 // Again, same parameterization rules apply.

For an ArrayListor a HashMap, the clearAllmethod might look like this:

对于 anArrayList或 a HashMap,该clearAll方法可能如下所示:

public class ModuleState()
{
    public void clearAll()
    {
          members.clear();
    }
}

This method won't need to change.

这种方法不需要改变。

回答by Bohemian

Make an inner class to hold the fields, then replace thatinstance when you want to reset. The write to the field would make the change to all three fields essentially atomic.

创建一个内部类来保存字段,然后在您想要重置时替换实例。写入字段将使所有三个字段的更改基本上是原子的。

public class ModuleState {

private static volatile ModuleState instance;

private static class Values {
    A a;
    B b;
    C c;
}
private volatile Values values = new Values()(

private ModuleState (){}

public ModuleState getInstance(){
    if (instance==null) {
        synchronized (ModuleState.class) {
            if (instance==null) {
                instance = new ModuleState();
            }
        }
    }

    return instance;
}

public synchronized A getA() {
     return values.a;
}

public synchronized void reset() {
    values = new Values();
}

By the way, your null checking initialization code was not threadsafe. I fixed that too.

顺便说一句,您的空检查初始化代码不是线程安全的。我也修好了。

Note that to make this work, you must make the reference to valuesvolatile and synchronize all access to it, otherwise (due to the java memory model) other threads than the one that calls reset() may see the old reference.

请注意,要完成此操作,您必须引用valuesvolatile 并同步对它的所有访问,否则(由于 Java 内存模型)除调用 reset() 的线程之外的其他线程可能会看到旧引用。

回答by gluckonavt

May be this can help you:

可能这可以帮助您:

public class SingletonBean {

    private static SingletonBean instance = new SingletonBean();
    private static Object privateMutex = new Object();

    private SingletonBean() {
        //to prevent instantiation
    }



public class ObjectsContainer {
    private Object A;
    private Object B;
    private Object C;

    public Object getA() {
        return A;
    }

    public void setA(Object a) {
        A = a;
    }

    public Object getB() {
        return B;
    }

    public void setB(Object b) {
        B = b;
    }

    public Object getC() {
        return C;
    }

    public void setC(Object c) {
        C = c;
    }
}

    private ObjectsContainer objectsContainer;

    private void resetObjectsContainer() {
        objectsContainer = new ObjectsContainer();
    }

    public static SingletonBean getInstance() {
        return SingletonBean.instance;
    }

    public static void clearAll() {
        synchronized (privateMutex) {
            SingletonBean.getInstance().resetObjectsContainer();
        }
    }

    public static ObjectsContainer getObjectsContainer() {
        synchronized (privateMutex) {
            return instance.objectsContainer;
        }
    }
}

public class SomeClass {
    public void someMethod() {
        SingletonBean.getObjectsContainer().getA();
    }
}