一,定义
确保一个类只有一个实例,并提供一个全局访问点。
二,各种单件类
(1)经典单件类
/**
* 经典单例类(不是线程安全的)
*/
public class Singleton {
// 利用一个静态变量记录Singleton的唯一实例
private static Singleton uniqueInstance;
// 把构造器声明为私有的,只有Singleton内部的方法才可以调用
private Singleton() {}
// 获得Singleton实例的全局访问点。 如果实例变量不为空则直接返回,如果为空则创建。
// 如果我们不需要这个实例,它就永远不会被创建,这就是延迟实例化,也叫懒加载。
// getInstance()这个方法是静态的,这意味着它是一个类方法,可以在代码的任何地方使用Singleton.getInstance()访问实例。
public static Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// 其他方法
public String getDescription() {
return "I'm a classic Singleton!";
}
}
(2)处理多线程
/**
* 单例类(处理多线程)
*/
public class Singleton {
protected static Singleton uniqueInstance;
protected Singleton() {}
// 在getInstance()方法中增加synchronized关键字,我们迫使每个线程进入这个方法之前,
// 要先等候其他线程离开该方法,即不会有两个线程同时进入该方法
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
(3)优化多线程一(减少使用synchronized同步)
/**
* 单例类(“急切”加载,也叫“饿汉加载”,不用使用同步了)
*/
public class Singleton {
// 在静态初始化器中创建单件实例,保证了线程安全
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
// 已有实例,直接返回使用
public static Singleton getInstance() {
return uniqueInstance;
}
}
(4)优化多线程二(使用双重检查加锁)
/**
* 单例类(双重检查加锁)
*/
public class Singleton {
// volatile关键字确保:当uniqueInstance被初始化成Singleton实例时,多个线程能正确处理uniqueInstance变量
private volatile static Singleton uniqueInstance;
private Singleton() {}
// 首先检查是否已经创建实例,如果未创建,才使用同步。这样一来,只有第一次会同步,
// 而且这个同步只会发生一次,这将大大提高程序的性能。
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
三,小结
个人理解就是,单件类没有公开的构造方法,若想得到单件类的实例对象,没有其他路可走,只能通过唯一的全局访问点去获得,而全局访问点这条路上又设置了一些限制,确保只能产生一个单件对象,这个限制就是,判断是否已经创建了单件对象,创建了,则直接返回该对象,不会再创建另一个,没创建则创建一个,也是唯一一个对象。这样就保证了单件对象的唯一性。