单例模式的目标就是让目标类只能有一个实力类。它的实现方式有以下几种方式,我们分别来进行分析一下,最后我们看看单例模式在实际当中的应用。
第一种方式:在该类中初始化一个该类的类变量,每次获取该类的实例化对象的时候直接把这个类变量返回出去。
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {} //为了外部类不能直接new,所以改为private
public static Singleton getInstance(){
return singleton;
}
}
这里是在类加载的时候就已经初始化了一个该类的类变量,每次获取到的对象实际上就是这个类变量。注意此处的构造方法改成了private的,这样做的目的是为了防止在类外部直接对该类进行new操作,从而保证该类至始至终都只有这一个对象。
不过这样做有个缺点,不管我最后用不用得到这个类的对象,只要类加载了,那个类对象就已经实例化了。不管你需不需要我,我就在那里默默地等着你。这样算是一种浪费吧。
第二种方式:是第一种方式的改良版,在第一次调用获取对象的方法的时候进行实例化。
public class Singleton {
private static Singleton singleton;
private Singleton() {} //为了外部类不能直接new,所以改为private
public static Singleton getInstance(){
if(singleton == null){ //第一次调用该方法的时候初始化
singleton = new Singleton();
}
return singleton;
}
}
这样加了一个判断,类对象如果没有实例化就实例化之后再返回,如果已经实例化就直接返回。这样就既保证了该类只有一个对象,同时又能保证该类只有在调用了实例化方法之后才会被初始化。
这种写法不宜用在多线程中,如果在多线程中这样实现,可能会出现这个类对象被多次实例化,其原因就是多个线程都进了上面的if判断,这种方式不是单例模式所期望的。
第三种方式:对调取对象的方法上面添加关键字synchronized可以实现线程安全。
public class Singleton {
private static Singleton singleton;
private Singleton() {} //为了外部类不能直接new,所以改为private
public static synchronized Singleton getInstance(){
if(singleton == null){ //第一次调用该方法的时候初始化
singleton = new Singleton();
}
return singleton;
}
}
这种方式虽然能够保证线程安全,但是这同时也让别的线程需要调用该方法的时候出现等待。其实我们真正希望的只是保证方法中的实例化的那部分代码是线程安全且只执行一次即可。
第四种方式:保证初始化的时候线程安全。
public class Singleton {
private static Singleton singleton;
private Singleton() {} //为了外部类不能直接new,所以改为private
public static Singleton getInstance(){
if(singleton == null){ //第一次调用该方法的时候初始化
synchronized(Singleton.class){
if(singleton == null){ //只保证此处线程安全即可
singleton = new Singleton();
}
}
}
return singleton;
}
}
这样我们把关键字synchronized加在初始化的地方就可以了。这样既能保证该类只会实例化一次,同时又能保证调取对象的方法不会因为多线程的缘故造成无效的等待。
下面我们看看单例模式在实际中的应用。将代码定位到jdk里面的类Runtime中,我们就会发现其实Runtime就是一个采用单例模式实现的类,而且采用的是第一种实现方式。下面我们来看看它的源码。
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
.
.
.
怎么样,学会单例模式的使用方式和注意事项了么。越是前面的方法越简单越快捷,同时弊端越多,采用什么样的实现方式根据实际业务需求,采用最佳的实现方式即可。