单例模式有饿汉式和懒汉式两种
饿汉式是当类加载时就创建类实例,不管你用不用,先创建再说,然后每次调用的时候就不需要进行判断,节省了运行时间。
/**
* 饿汉式单例实现的示例
*/
public class Singleton {
/**
* 定义一个变量来存储创建好的类实例,直接在这里创建类实例,只会创建一次
*/
private static Singleton uniqueInstance = new Singleton();
/**
* 私有化构造方法,好在内部控制创建实例的数目
*/
private Singleton(){
//
}
/**
* 定义一个方法来为客户端提供类实例
* @return 一个Singleton的实例
*/
public static Singleton getInstance(){
//直接使用已经创建好的实例
return uniqueInstance;
}
/**
* 示意方法,单例可以有自己的操作
*/
public void singletonOperation(){
//功能处理
}
/**
* 示意属性,单例可以有自己的属性
*/
private String singletonData;
/**
* 示意方法,让外部通过这些方法来访问属性的值
* @return 属性的值
*/
public String getSingletonData(){
return singletonData;
}
}
懒汉式是每次获取实例的时候进行判断,看看是否需要进行创建实例,需要判断的时间,当没人使用的时候,就不会创建实例,节省内存空间。
public class Singleton {
//4:定义一个变量来存储创建好的类实例
//5:因为这个变量要在静态方法中使用,所以需要加上static修饰
private static Singleton instance = null;
//1:私有化构造方法,好在内部控制创建实例的数目
private Singleton(){
}
//2:定义一个方法来为客户端提供类实例
//3:这个方法需要定义成类方法,也就是要加static
public static Singleton getInstance(){
//6:判断存储实例的变量是否有值
if(instance == null){
//6.1:如果没有,就创建一个类实例,并把值赋值给存储类实例的变量
instance = new Singleton();
}
//6.2:如果有值,那就直接使用
return instance;
}
}
线程安全方面:
1.不加同步的懒汉式是不安全的,因为当两个线程调用 getInstance()方法时,A线程已经判断结束,但是还没有创建实例,而B线程正在进行判断,这个时候就会出错创建出两个实例出来。
2.饿汉式是安全的,因为虚拟机在装载类的时候不会出现并发的状况
3.实现懒汉式的线程安全问题,加上synchronized,但是这样一来速度更慢饿了
public static synchronized Singleton getInstance(){}
4.双重检查枷锁机制:并不是每次进入getInstance方法都要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在才进入下面的同步快,这是一重检查。进入同步块后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。
双重检查枷锁机制的实现会使用一个关键字volatile,它的意思是:被volatile修饰的变量的值不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确处理该变量。
public class Singleton {
/**
* 对保存实例的变量添加volatile的修饰
*/
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;
}
}
提示:由于volatile关键字可能会屏蔽掉虚拟机中的一些必要的代码优化,所以运行效率并不高,因此没有必要不要使用。
类级内部类:有static修饰的成员式内部类。
类级内部类相当于其外部类的static成分,他的对象与外部类对象间不存在依赖关系,因此可直接创建。
类级内部类相当于其外部类的成员,只有在第一次被使用的时候才会被加载。
public class Singleton {
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
* 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
*/
private static class SingletonHolder {
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static Singleton instance = new Singleton();
}
/**
* 私有化构造方法
*/
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}