工作中因为不熟悉设计模式导致犯了一个较严重的错误,幸好没有给公司造成损失。如今才知道设计模式的重要性,下面让这次错误的罪魁祸首-单例模式登场。
单例模式,顾名思意,在一个应用系统中,仅存在一个实例。这样的实例很常见,例如:线程池、连接池、缓存等等。
单例是一个系统的共享点,任何需要该单例的对象,都会去共享点中去取,这也是单例存在的意义。
假设要做一个单例demo,现给出如下示例:
public class MySingleton {
public static MySingleton myInstance;
private MySingleton(){
System.out.println("do something!");
}
public static MySingleton getMyInstance(){
if(myInstance == null){
myInstance = new MySingleton();
}
return myInstance;
}
}
这个程序在遇见多线程的情况下,会有严重的弊端。假设thread1与thread2同时调用getMyInstance()方法,同时判断myInstance且都为空,那么它们会各自产生一个实例,结果,单例失效了。
要解决多线程的问题,有3个方法:
1.给getMyInstance()进行同步,每个线程进入该方法时,都要等待前一个线程处理完后再进入。
public class MySingleton {
public static MySingleton myInstance;
private MySingleton(){
System.out.println("do something!");
}
public static synchronized MySingleton getMyInstance(){
if(myInstance == null){
myInstance = new MySingleton();
}
return myInstance;
}
}
2.在JVM加载该类的时候立即创建这唯一的实例
public class MySingleton {
public static MySingleton myInstance = new MySingleton();
private MySingleton(){
System.out.println("do something!");
}
public static MySingleton getMyInstance(){
return myInstance;
}
}
3.仅第一次实例不存在的时候进行同步,后续都不同步。这就是double-checked locking
public class MySingleton {
public static MySingleton myInstance;
private MySingleton(){
System.out.println("do something!");
}
public static MySingleton getMyInstance(){
if(myInstance == null){
synchronized(MySingleton.class){
if(myInstance == null){
myInstance = new MySingleton();
}
}
}
return myInstance;
}
}
对于以上三种方法,我们分别有如下分析:
1.这个方法理论上是可行的,但是实际的不可取的,这会严重的降低性能
2.对于频繁使用的单例,我们可以用2
3.这种需要时才创建对象的方式,不会占用太多资源,也是不错的。
总之,使用单例时一定要注意性能和资源上的限制,选择适当的方案运用单例,希望osc友们运用得当。