创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是“将对象的创建与使用分离”。
1.单例设计模式
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供 了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例设计模式分类两种:
饿汉式:类加载就会导致该单实例对象被创建
懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建
1.1 饿汉式
由于类加载时创建对象,后续一直不使用的话会造成内存浪费。
1.1.1 方式一:静态变量方式
public class Singleton {
//1.私有构造方法,私有构造方法是让外界不能创建该类的对象
private Singleton(){
}
//2.在本类中创建本类对象
private static Singleton singleton=new Singleton();
//3.提供一个公共的访问方式让外界获取该对象
public static Singleton getSingleton(){
return singleton;
}
}
public class Client {
public static void main(String[] args) {
//创建对象
Singleton singleton = Singleton.getSingleton();
Singleton singleton2 = Singleton.getSingleton();
System.out.println(singleton2==singleton);
}
}
根据结果可以知道,创建的Singleton为相同对象。
1.1.2 方式二:静态代码块
public class Singleton {
//1.私有构造方法
private Singleton(){
}
//2.声明Singleton类型的变量
private static Singleton singleton;
//在静态代码块中进行赋值
static {
singleton=new Singleton();
}
//3.提供一个公共的访问方式让外界获取该对象
public static Singleton getSingleton(){
return singleton;
}
}
1.2 懒汉式
1.2.1 方式一:线程不安全
public class Singleton {
//1.私有构造方法
private Singleton(){
}
//2.在成员位置创建该类的对象
private static Singleton singleton;
//3.提供一个公共的访问方式让外界获取该对象
public static Singleton getSingleton(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
1.2.2 方式二: 线程安全
public class Singleton {
//1.私有构造方法
private Singleton(){
}
//2.在成员位置创建该类的对象
private static Singleton singleton;
//3.提供一个公共的访问方式让外界获取该对象
public static synchronized Singleton getSingleton(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
该方法由于在getSingleton方法内加了锁,该方法里面除了写操作还是读操作,这样统一加锁对性能有很大的影响
1.2.3 方式三 双重检查锁(推荐)
public class Singleton {
//1.私有构造方法
private Singleton(){
}
//2.在成员位置创建该类的对象
private static volatile Singleton singleton;
//3.提供一个公共的访问方式让外界获取该对象
public static Singleton getSingleton(){
//第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实际
if(singleton == null) {
synchronized (Singleton.class) {
//抢到锁之后再次判断是否为空
if(singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
在多线程的情况下,可能会出现空指针问题,出现问 题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。因此需要添加volatile。添加 volatile 关键字之后的双重检查锁模式是一种比较好的单例实现模式,能够保证在多线程 的情况下线程安全也不会有性能问题。
1.2.4 方式四 双静态内部类方式
public class Singleton {
//私有构造方法
private Singleton() {}
private static class SingletonHolder {
private static final Singleton singleton = new Singleton();
}
//对外提供静态方法获取该对象
public static Singleton getSingleton() {
return SingletonHolder.singleton;
}
}
静态内部类单例模式中实例由内部类创建,由于 JVM 在加载外部类的过程中, 是不会加载静态 内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。
静态内部类单例模式是一种优秀的单例模式,是开源项目中比较常用的一种单例模式。在没有加任 何锁的情况下,保证了多线程下的安全,并且没有任何性能影响和空间的浪费。
1.3 枚举方式(饿汉式)
枚举类实现单例模式是极力推荐的单例实现模式,因为