其实很早之前就明白了单例,但是因为在大学的时候课程设计都用不到单例,所以仅仅是知道单例,并没有仔细地思考过它的用途。今天是16年11月30号,今天因为项目需要需要写一个单例。在自己需要用单例的时候,为了程序的性能,自然要选择最优的单例。下面就各种单例说一说它们的优缺点。
1 懒汉模式
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance==null){
instance = new Singleton();
}
return instance;
}
}
这种方式的缺点很明显,就是线程不安全,当同时访问这个单例时,在创建单例的期间有人访问这个单例就又会创造一个实例,造成错误。
2 懒汉模式改进版
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance==null){
instance = new Singleton();
}
return instance;
}
}
这种方式线程上虽然安全,但是因为实际只有很小一部分情况需要用到锁,加锁降低了效率。所以这个方法也是不好的,线程虽然安全了,但是效率很低。
3 恶汉模式
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
这种方式的优缺点也很明显,优点是线程安全的,但是却浪费空间。在不使用这个类的时候就实例化了这个类。当然有很多情况这个方式是不错的,比如随着程序的启动就 要实例化的单例。今天就碰到了这种需求,但是我还是选择了最优的单例方式。
4 双重检测模式
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance==null){
synchronized(Singleton.class){
if(instance==null){
instance = new Singleton()
}
}
}
return instance;
}
}
这里说一下为什么要双重检测,因为第一次判断为空的时候,在给.class文件加锁之前可能这个类已经被实例化了,所以需要再判断一次。这里说一下如果对方法加锁是线程
安全的,但是效率不好,因为一时间只有一个线程可以调用这个方法。现在是给.class文件加锁,也就是说如果这个类已经实例化了,就可以直接调用了,唯一产生竞争的瞬间就是在实例化第一次的时候。