一、 单例模式的定义
单例模式是确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点,它隐藏了其所有的构造方法,属于创建型模式。
二、单例模式的常见写法
1. 饿汉式单例
定义
在单例首次加载的时候就创建实例
优点
写法简单、执行效率高、性能高(因为没加锁),不存在线程安全问题
缺点
在某些情况下可能会造成内存的浪费。因为在类加载的时候单例就被初始化了,如果这些类没有使用,则会浪费内存空间 所以,在需要大量创建单例的情况下,不适合使用饿汉式单例
代码
写法一:在属性定义的时候就初始化属性
//饿汉式的第一种写法
public class HungrySingleTon1 {
private static final HungrySingleTon1 h = new HungrySingleTon1();
//私有化构造器
private HungrySingleTon1(){};
//提供对外的获取单例方法
public static HungrySingleTon1 getInstance(){
return h;
}
}
写法二:在静态代码块中初始化实例
//饿汉式的第二种写法
public class HungrySingleTon2 {
private static final HungrySingleTon2 h ;
//在静态代码块中初始化
static {
h = new HungrySingleTon2();
}
//私有化构造器
private HungrySingleTon2(){};
//提供对外的获取单例方法
public static HungrySingleTon2 getInstance(){
return h;
}
}
2. 懒汉式单例
2.1 普通的懒汉式单例
定义
在外部第一次调用的时候才会创建实例
优点
相较于饿汉式单例,懒汉式单例节省了内存,在用到的时候才会初始化
缺点
存在线程不安全的问题 解决线程安全的办法: 1.在getInstance方法处加synchronized 2.使用双重检验锁的单例模式
代码
//简单的懒加载
public class LazySingleTon {
//私有化实例对象
private static LazySingleTon instance;
//私有化构造器
private LazySingleTon(){};
/**
* 写法一:提供获取实例的方法
* 优点:相较于饿汉式,这里节省了内存空间,需要用到单例对象的时候才会初始化;
* 缺点:存在线程安全问题
*/
public static LazySingleTon getInstance(){
if (null == instance){
instance = new LazySingleTon();
}
return instance;
}
/**
* 解决办法一:给方法加锁,因为是静态方法,所以加的是类锁
* 解决办法二:用双重检验锁的单例模式,见LazyDoubleChecktSingleTon
*/
public synchronized static LazySingleTon getInstance2(){
if (null == instance){
instance = new LazySingleTon();
}
return instance;
}
}