一、饿汉式
public class Singleton{
//定义一个变量来存储创建好的类实例,直接在这里创建,只能创建一次
private static Singleton uniqueInstance = new Singleton();
//私有化构造方法,可以在内部控制创建实例的数目
private Singleton(){
//
}
//定义一个方法来为客户端提供类实例
public static Singleton getInstance(){
return uniqueInstance;
}
}
最简单的单例实现,典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要在判断了,节省了运行时间。
二、懒汉式
public class Singleton{
//定义一个变量来存储创建好的实例
private static Singleton uniqueInstance = null;
//私有化构造方法,可以在内部控制创建实例的数目
private Singleton(){
//
}
//定义一个方法来为客户端提供类实例
public static synchronized Singleton getInstance(){
//判断存储实例的变量是否有值
if(uniqueInstance == null){
//如果没有,就创建一个类实例,并把值赋给存储类实例的变量
uniqueInstance = new Singleton();
}
//如果有就直接使用
return uniqueInstance();
}
}
时间-空间上刚好与饿汉相反,可以实现延迟加载,但是需要注意多线程调用的效率问题。
三、内部类实现
public class Singleton{
/*类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例没有绑
*定关系,而且在由在调用时才会装载,从而实现了延迟加载
*/
private static class SingletonHolder{
//静态初始化器,由JVM来保证线程安全
private static Singleton instance = new Singleton();
}
private Singleton(){
}
private static Singleton getInstance(){
return SingletonHolder.instance;
}
}
由虚拟机来保证它的线程安全性。
四、缓存方式
import java.util.* ;
public class SingletonCache{
private final static String DEFAULT_KEY = "One" ;
private static Map map = new HashMap
private SingletonCache(){
//
}
public static SingletonCache getInstance(){
SingletonCache instance = (SingletonCache)map.get(DEFAULT_KEY) ;
if(instance==null){
instance = new SingletonCache() ;
map.put(DEFAULT_KEY,instance) ;
}
}
}
该种实现方式可以扩展为实例数量固定的情形,如要求某个类最多创建3个实例的情形。
五、枚举方式
public enum Singleton{
//定义一个枚举的元素,它代表了Singleton的一个实例
uniqueInstance ;
private Singleton() {
//准备初始化工作
}
public void singletonOperate(){
//功能处理
}
}
最简单、高效、安全的实现方式。
六、双重加锁
public class Singleton{
private volatile static Singleton instance = null ;
private Singleton(){
}
public static Singleton getInstance(){
//先检查实例是否存在,如果不存在才进入下面的同步块
if(instance == null){
//同步块,线程安全地创建实例
synchronized(Singleton.class){
//再次检查实例是否存在,如果不存在才真正地创建实例
if(instance == null){
instance = new Singleton() ;
}
}
}
return instance ;
}
}
使用“双重检查加锁”的方式来实现,就可以既实现线程安全,又能够使性能不受到大的影响。所谓双重检查加锁机制,指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。
双重检查加锁机制的实现会使用一个关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。