在Java中清除Singleton实例

时间:2013-05-12 09:36:32

标签: java design-patterns singleton

我有一个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;
}

}

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

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

    ..
    ..
}

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

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

5 个答案:

答案 0 :(得分:11)

怎么样......

public static volatile ModuleState instance = null;

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

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

干杯!

答案 1 :(得分:2)

不,这种方法是完全可以接受的。你当然是以某种方式同步对这些状态对象的访问,对吧?否则你会冒一个人看到半清的配置对象。

你可以做的另一件事就是将来自己对抗未来添加的任何额外状态就是将你所有的状态存储在HashMap中,例如,而不是单个字段。这样,clear()的hashmap确保擦除所有状态,并在将来添加任何额外状态变得更安全

答案 2 :(得分:1)

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

但是,如果你想稍微清理它,为什么不只是有一个内部列表,如:

 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.

另一种选择是拥有一个HashMap,将关键词绑定到该成员。

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

对于ArrayListHashMapclearAll方法可能如下所示:

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

此方法无需更改。

答案 3 :(得分:0)

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

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

顺便说一下,你的空检查初始化代码不是线程安全的。我也解决了这个问题。

注意,要使其工作,您必须引用values volatile并同步对它的所有访问,否则(由于java内存模型)其他线程而不是调用reset()的线程可能会看到旧参考。

答案 4 :(得分:0)

可能这可以帮到你:

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