6

我有一个 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() 方法中添加一行来重置新变量。

4

5 回答 5

12

关于什么 ...

public static volatile ModuleState instance = null;

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

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

干杯!

于 2013-05-12T09:40:19.343 回答
2

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

您可以做的另一件事来证明自己免受将来添加的任何额外状态的影响,例如,将所有状态存储在 HashMap 中,而不是单个字段。这样,对 hashmap 进行 clear() 可以确保擦除所有状态,并且将来添加任何额外的状态会变得更安全

于 2013-05-12T09:40:04.843 回答
1

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

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

 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.

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

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

这种方法不需要改变。

于 2013-05-12T10:04:52.237 回答
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();
    }
}
于 2013-05-12T10:28:38.797 回答
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();
}

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

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

于 2013-05-12T10:17:48.487 回答