java-设计模式-单例模式
单例模式
-
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。
-
属于创建型模式,提供了一种创建对象的最佳方式。
-
一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,提供唯一的对象访问方式方式,可以直接访问,不需要实例化该类的对象。
-
注意:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
饿汉式单例
-
饿汉式单例是单例模式中最简单的一种单例实现
-
饿汉式单例在类加载的时候就会对类对象进行加载,但会浪费内存资源,属于常用方式,但容易产生垃圾对象
-
饿汉式单例基于java的classloader机制实现了多线程安全
实现
public class Hungry { //单例模式-->饿汉式 //私有化无参构造器 private Hungry(){} //创建私有类对象 private static Hungry hungry = new Hungry(); //将类对象返回 public static Hungry getInstance(){ return hungry; } }
懒汉式单例
-
属于单例模式的一种基本实现,类加载时不会自动加载,
public class Lazy { //创建私有类实例 private static Lazy lazy; //私有化无参构造 private Lazy(){} //返回类实例 public static Lazy getInstance(){ if (lazy==null){ lazy = new Lazy(); } return lazy; } }
-
但是这种方式线程不安全,在多线程环境下不能正常工作,可以使用synchronized进行加锁,使得线程安全
//使用双重检测加锁的方式实现线程安全 public class LazySafe { private static LazySafe lazySafe; private LazySafe(){} public static LazySafe getInstance(){ if (lazySafe == null){ synchronized (LazySafe.class){ if (lazySafe==null){ lazySafe = new LazySafe(); } } } return lazySafe; } }
-
上面的方式的实现不是原子性操作,多线程环境中可能出现指令重排的现象,从而导致程序出现问题,这是我们需要加上volatile进行修饰
- 原子性是一个或某多个操作只能一个线程执行完之后,另一个线程才能开始执行该操作
- 也就是说这些操作是不可分割的,线程不能在这些操作上交替执行
public class LazySafe { //使用了volatile private volatile static LazySafe lazySafe; private LazySafe(){} public static LazySafe getInstance(){ if (lazySafe == null){ synchronized (LazySafe.class){ if (lazySafe==null){ lazySafe = new LazySafe(); } } } return lazySafe; } }
枚举实现单例
-
这种方式是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
-
不能通过 reflection attack(反射) 来调用私有构造方法。
-
同时,使用该方式创建得到的单例对象时线程安全的
-
建议使用该方式创建单例对象
public enum SingleEnum { INSTANCE; public SingleEnum getInstance(){ return INSTANCE; } }