这个就不用多作介绍了。平常项目过程中用的也很多,也是最常见的设计模式之一。顾名思义,主要功能便是每次调用方法获得的都是同一个对象,而不是重新创建。
下面列举几个常见的方法。
方法一:最简单,最不安全
public class Singleton {
private static Singleton singleton;
/**
*私有构造方法,防止被实例化
*/
private Singleton() {
}
//线程不安全
public static Singleton getInstance1(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
代码很简单,也很直接。但是有很大一个问题便是多线程状况下并不能保证对象的唯一性。因此很不推荐,这里也就不多做讨论了。
方法二:加入synchronized关键字
public class Singleton {
private static Singleton singleton;
/**
*私有构造方法,防止被实例化
*暂时注释掉
*/
private Singleton() {
}
//线程安全但是性能上有所下降,每次getInstance2()都要加锁,事实上只有第一次需要,之后就不需要了。
public static synchronized Singleton getInstance2(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
方法三:双重判断
public static Singleton getInstance3(){
if(singleton == null){
synchronized (singleton) {
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
这个方法创建避免了每次调用都加锁的问题,同时也保证了线程安全。是推荐方法。
方法四:通过JVM的内部机制来实现
public static class SingletonFactory{
private static Singleton singleton = new Singleton();
}
public static Singleton getInstance4(){
return SingletonFactory.singleton;
}
单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候, JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕。这个也是我从其他地方看到的,通过内部机制来实现,亲测可行!!
方法五:在第一次调用的时候加上锁
private static synchronized void syncInit() {
if (singleton == null) {
singleton = new Singleton();
}
}
public static Singleton getInstance5() {
if (singleton == null) {
syncInit();
}
return singleton;
}
方法二每次调用都要加锁,而这种方法恰好解决了这个问题。效率上也还可以。
上面就是几个常见的单例方法,方法三和四是比较推荐的。