一、介绍
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(这个方法是静态方法)。
二、单例模式的八种方式:
- 饿汉式(静态常量)
- 饿汉式(静态代码块)
- 懒汉式(线程不安全)
- 懒汉式(线程安全,同步方法)
- 懒汉式(线程安全,同步代码块)
- 双重检查
- 静态内部类
-
三、饿汉式(静态常量)
1、步骤如下:
构造器私有化(防止外部new)
- 类的内部创建对象
向外暴露一个静态的公共方法获取这个类的实例—-getInstance()
public class SingletonTest01 {// 本类内部创建静态实例private static final SingletonTest01 SINGLETON = new SingletonTest01();// 构造器私有private SingletonTest01() {}// 对外提供获取该类实例的静态方法public static SingletonTest01 getInstance() {return SINGLETON;}}
2、优缺点说明
四、饿汉式(静态代码块)
public class SingletonTest02 {// 本类内部创建静态实例private static final SingletonTest02 SINGLETON;// 静态代码块static {SINGLETON = new SingletonTest02();}// 构造器私有private SingletonTest02() {}// 对外提供获取该类实例的静态方法public static SingletonTest02 getInstance() {return SINGLETON;}}
五、懒汉式(线程不安全)
public class SingletonTest03 {// 本类内部创建静态实例private static SingletonTest03 SINGLETON;// 构造器私有private SingletonTest03() {}// 对外提供获取该类实例的静态方法--当使用该方法时,采取实例化该类对象--实现懒加载public static SingletonTest03 getInstance() {if (SINGLETON == null) {SINGLETON = new SingletonTest03();}return SINGLETON;}}
六、懒汉式(线程安全,同步方法)
public class SingletonTest04 {// 本类内部创建静态实例private static SingletonTest04 SINGLETON;// 构造器私有private SingletonTest04() {}// 加锁---synchronizedpublic static synchronized SingletonTest04 getInstance() {if (SINGLETON == null) {SINGLETON = new SingletonTest04();}return SINGLETON;}}
七、懒汉式(线程不一定安全,同步代码块)
public class SingletonTest04 {// 本类内部创建静态实例private static SingletonTest04 SINGLETON;// 构造器私有private SingletonTest04() {}// 加锁---synchronized--同步代码块public static SingletonTest04 getInstance() {if (SINGLETON == null) {synchronized (SingletonTest03.class) {if (SINGLETON == null) {SINGLETON = new SingletonTest04();}}}return SINGLETON;}}
八、双重检查(推荐)
public class SingletonTest05 {// 本类内部创建静态实例// volatile--保证可见性--即一个线程改变了值,另一个线程可以立马感知到改变的值private static volatile SingletonTest05 SINGLETON;// 构造器私有private SingletonTest05() {}public static SingletonTest05 getInstance() {if (SINGLETON == null) {synchronized (SingletonTest03.class) {if (SINGLETON == null) {SINGLETON = new SingletonTest05();}}}return SINGLETON;}}
拓展:
(1)使用反射破解单例模式
public class SingletonTest {public static void main(String[] args) throws Exception{SingletonTest05 s1 = SingletonTest05.getInstance();SingletonTest05 s2 = SingletonTest05.getInstance();System.out.println(s1);System.out.println(s2);/*** 装载一个类并且对其进行实例化的操作。* 装载过程中使用到的类加载器是当前类。*/// 反射破解单例模式// com.example.demo.thread.SingletonTest05:单例类的全路径类名//Class<SingletonTest05> clazz = (Class<SingletonTest05>) Class.forName("com.example.demo.thread.SingletonTest05");Class<SingletonTest05> clazz = SingletonTest05.class;// getDeclaredConstructor():此方法返回具有指定参数列表构造函数的构造函数对象。使用这个方法私有的构造器也可以拿到Constructor<SingletonTest05> c = clazz.getDeclaredConstructor(null);// 设置在使用构造器的时候不执行权限检查c.setAccessible(true);SingletonTest05 singletonTest05 = c.newInstance();System.out.println(singletonTest05);}}
解决方法:
public class SingletonTest05 {private static volatile SingletonTest05 SINGLETON;// 构造器私有private SingletonTest05() {// 在这里防止反射破解单例模式// 此时若再使用反射破解单例模式,则直接抛出异常if (SINGLETON != null) {throw new RuntimeException("禁止使用反射破解单例模式!");}}public static SingletonTest05 getInstance() {if (SINGLETON == null) {synchronized (SingletonTest05.class) {if (SINGLETON == null) {SINGLETON = new SingletonTest05();}}}return SINGLETON;}}
(2)使用序列化破解单例模式
public class SingletonTest1 {public static void main(String[] args) throws Exception{SingletonTest05 s1 = SingletonTest05.getInstance();SingletonTest05 s2 = SingletonTest05.getInstance();System.out.println(s1);System.out.println(s2);// 序列化方式破解单例模式try (FileOutputStream fos = new FileOutputStream("d:/a.txt");ObjectOutputStream oos = new ObjectOutputStream(fos);ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/a.txt"));) {oos.writeObject(s1);SingletonTest05 s3 = (SingletonTest05) ois.readObject();System.out.println(s3);} catch (Exception e) {e.printStackTrace();}}}
解决方法:
public class SingletonTest05 implements Serializable {private static volatile SingletonTest05 SINGLETON;// 构造器私有private SingletonTest05() {// 在这里防止反射破解单例模式// 此时若再使用反射破解单例模式,则直接抛出异常if (SINGLETON != null) {throw new RuntimeException("禁止使用反射破解单例模式!");}}// 此方法可防止序列化破解单例模式// 此时若再使用序列化破解单例模式,则直接返回已经创建好的单例对象private Object readResolve(){return SINGLETON;}public static SingletonTest05 getInstance() {if (SINGLETON == null) {synchronized (SingletonTest05.class) {if (SINGLETON == null) {SINGLETON = new SingletonTest05();}}}return SINGLETON;}}
九、静态内部类(推荐)
```java /**
- 静态内部类有两个特点:
- 1、当外部类被装载的时候,静态内部类并不会别装载
- 2、调用getInstance()时静态内部类才会被装载(JVM在装载类的时候是线程安全的) */ public class SingletonTest06 {
// 构造器私有private SingletonTest06() {}// 静态内部类private static class SingletonInstance {private static final SingletonTest06 SINGLETON = new SingletonTest06();}public static SingletonTest06 getInstance() {return SingletonInstance.SINGLETON;}
}
<a name="ymTjX"></a># 十、枚举(推荐)```javapublic enum SingletonTest07 {INSTANCE;public void method() {System.out.println("这是一个方法");}}// 测试类class TestDemo {public static void main(String[] args) {// 获取单例实例对象SingletonTest07 instance = SingletonTest07.INSTANCE;instance.method();}}
优点:
十一、总结

