Java设计模式之单例模式
2019-03-31 本文已影响0人
文艺小卿年
1. 什么是单例模式
为了避免不一致的状态,有时需要一个类只有一个对象,单例模式应运而生。
2. 单例模式的特点
2.1. 只能有一个实例
构造方法私有化,使之不能在类的外部通过new来实例化该对象
2.2. 它必须自行创建这个实例,并且用静态变量保存
2.3.它必须自行向外部类提供这个实例
3. 实现
3.1. 饿汉式
在类加载时直接创建对象,不管以后会不会使用该实例对象,先创建了再说(就像一个饥饿的人,着急要食物的样子)。在方法调用之前,实例就已经被创建了,所以是线程安全的。
3.1.1. 直接实例化
public class Singleton1 {
public static final Singleton1 INSTANCE = new Singleton1();
private Singleton1() {
}
}
3.1.2. 枚举类型
直接在该枚举类中给出该实例,因为枚举类型就是该类型的对象时有限的几个,限定为一个,就成了单例。
public enum Singleton2 {
INSTANCE;
}
3.1.3. 静态代码块
public class Singleton3 {
public static final Singleton3 INSTANCE;
static {
INSTANCE = new Singleton3();
}
private Singleton3() {
}
}
这种方法和直接实例化有点相似,但是比直接实例化复杂,那我们为什么还要用这个呢?有些时候,需要有参数的构造器,如果在创建对象的时候直接传入参数,后期不方便维护,所以一般会把参数放到配置文件中,然后在静态代码块中加载配置文件。
3.2. 懒汉式
懒汉式就是延迟创建对象,在使用的时候才进行实例化。
3.2.1. 延迟创建实例对象
public class Singleton4 {
public static Singleton4 instance;
private Singleton4() {
}
public static Singleton4 getInstance() {
if (instance == null) {
instance = new Singleton4();
}
return instance;
}
}
该方法在类被加载的时候,并没有创建以及分配内存空间,只有当getInstance方法第一次被调用的时候,才初始化instance变量,并分配内存。这种方法适合于单线程
3.2.2. 线程安全的“懒汉模式”
public class Singleton5 {
public static Singleton5 instance;
private Singleton5() {
}
public static synchronized Singleton5 getInstance() {
if (instance == null) {
instance = new Singleton5();
}
return instance;
}
}
通过关键字synchronized对getInstance方法进行了线程同步,但是这样每次获得类的实例时,都要对getInstance方法进行同步,效率低。
3.2.3. 双重检查
public class Singleton6 {
public static Singleton6 instance;
private Singleton6() {
}
public static Singleton6 getInstance() {
if (instance == null) {
synchronized (Singleton6.class) {
if (instance == null) {
instance = new Singleton6();
}
}
}
return instance;
}
}
使用双重检查的方式在每次实例化的时候都要先判断实例对象是否存在,这样,实例化代码只用执行一次,后面再次访问时,直接返回实例化对象。线程安全,且效率高。
3.2.4. 静态内部类式
public class Singleton7 {
private Singleton7(){
}
private static class Inner{
private static final Singleton7 INSTANCE =new Singleton7();
}
public static Singleton7 getInstance(){
return Inner.INSTANCE;
}
}
这种方式虽然也是采用类加载的机制来保证初始化实例时只有一个线程,但是不像饿汉式那样只要Singleton类被加载就会实例化,而是在需要实例化的时候,调用getInsatnce方法,才会加载内部类完成Singleton的实例化(静态内部类和非静态内部类一样,都是在被调用时才会被加载)