清除Java中的单例实例
我有一个单例类来保存应用程序模块的状态。 这个类只是有很多带有setter和getter的类变量:清除Java中的单例实例,java,design-patterns,singleton,Java,Design Patterns,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)
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;
..
..
}
public class ModuleState()
{
public void clearAll()
{
members.clear();
}
}
我的问题是:有一个更干净的方法来进行重置吗?是否可能在不重置每个类变量的情况下清除singleton实例本身
这种方法的问题是,我可能需要向ModuleState添加一个新的类变量。在这种情况下,我必须记住在clearAll()方法中添加一行来重置新变量。不,这种方法完全可以接受。当然,您正在以某种方式同步对这些状态对象的访问,对吗?否则,可能会有人看到半清除的配置对象 另一件事,你可以做的未来证明自己对任何额外的状态添加在未来是存储您的所有状态在一个HashMap,例如,而不是个别字段。通过这种方式,清除hashmap()可以确保删除所有状态,并且将来添加任何额外的状态都会变得更安全那么
public static volatile ModuleState instance = null;
public static void reset() {
instance = new ModuleState();
}
p.s.:根据下面的讨论:在多线程环境中,同步对实例的访问非常重要,因为JVM被允许访问其值。您可以如上所示使用。谢谢大家
干杯 为了符合单例模式,您需要维护相同的对象实例,因此您的方法是有意义的:更改成员 但是,如果您想稍微清理一下,为什么不创建一个内部列表,比如:
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.
对于ArrayList
或HashMap
,clearAll
方法可能如下所示:
public void clearAll(){
a=null;
b=null;
c=null;
..
..
}
public class ModuleState()
{
public void clearAll()
{
members.clear();
}
}
此方法不需要更改。创建一个内部类来保存字段,然后在需要重置时替换该实例。对字段的写入将使对所有三个字段的更改基本上是原子性的
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();
}
顺便说一下,您的空检查初始化代码不是线程安全的。我也修好了
请注意,要使此工作正常,必须将对
值的引用设置为volatile,并同步对它的所有访问,否则(由于java内存模型),调用reset()的线程以外的其他线程可能会看到旧的引用。这可能有助于您:
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();
}
}
单身汉不再是单身汉了。如果某些代码将getInstance()的结果缓存在某个地方,那么它将访问或修改状态的早期版本。在选择这个解决方案之前必须考虑到这一点。是的,你是对的:这有点违背了单身的想法。此外,可能需要同步此方法。但它仍然可以运行,不是吗?它必须以某种方式缓存它。只要调用ModuleState.getInstance().getA().getFoo()就有可能在另一个线程并行更改单例时访问过时状态。使getInstance()同步并不会改变任何事情。@JBNizet相同的unsafety参数可以应用于getA..Z
返回的单个对象,因此显然必须接受对“精度”的一些实际限制。使instance
易失性并使用这种方法可能是解决OP问题的一个非常好的方法。@JBNizet唯一最终安全的解决方案是一个庞大的类,它从不公开任何a..Z
对象,但只能查询它们所持有的叶原子值。整个类必须进行同步
,以便重置操作与每个get相互排斥。看起来单例模式可能不是最适合这里的。如果你有一个对象的状态,你需要完全重置它,这听起来像是你有构造函数做的事情。我需要找到一个充分的理由来引入上面的代码,因为IMO太复杂了。@Woody实际上,除了更简单的方法之外,它没有实现任何东西,它只允许客户端缓存“singleton”。但是拥有这样的协议没有内在的价值:坚持单例总是从getInstance
获取有什么不对?@MarkoTopolnik你在谈论这个问题时是不是这样说的“一个庞大的类,它从不公开任何a..Z对象,但只能查询它们所持有的叶原子值。整个类必须同步,以便重置操作与每个get互斥?顺便问一下,我喜欢这个解决方案,有什么缺点吗?这样安全吗?