目录
[TOC]
什么是单例模式
单例设计模式(Singleton Pattern)是一种常用的软件设计模式,它保证一个类只有一个实例,并提供一个全局访问点。这种模式在需要确保某个类只有一个实例的情况下非常有用,常用于管理共享资源或限制对象的创建。
单例模式应用场景
- 配置管理:在应用程序中,可能需要使用一些全局的配置信息,例如数据库连接字符串、日志级别等。这些配置信息通常只需要一份,因此可以使用单例模式来实现。通过单例模式,我们可以在应用程序启动时创建一个唯一的实例,并在整个应用程序中共享这个实例。这样可以避免多个线程或进程同时访问和修改配置信息,从而保证了配置信息的一致性和可靠性。
- 日志记录:在应用程序中,可能需要使用一个全局的日志记录器,用于记录应用程序的运行情况和错误信息。同样地,只需要一份日志记录器即可,因此可以使用单例模式来实现。通过单例模式,我们可以在应用程序启动时创建一个唯一的实例,并在整个应用程序中共享这个实例。这样可以避免多个线程或进程同时访问和修改日志记录器,从而保证了日志记录的一致性和可靠性。
- 缓存管理:在应用程序中,可能需要使用一个全局的缓存系统,用于缓存一些数据以提高应用程序的性能。同样地,只需要一份缓存系统即可,因此可以使用单例模式来实现。通过单例模式,我们可以在应用程序启动时创建一个唯一的实例,并在整个应用程序中共享这个实例。这样可以避免多个线程或进程同时访问和修改缓存系统,从而保证了缓存系统的一致性和可靠性。
- 资源管理:在应用程序中,可能需要使用一些全局的资源,例如文件句柄、网络连接等。这些资源通常只需要一份,因此可以使用单例模式来实现。通过单例模式,我们可以在应用程序启动时创建一个唯一的实例,并在整个应用程序中共享这个实例。这样可以避免多个线程或进程同时访问和修改资源,从而保证了资源的一致性和可靠性。
代码
懒汉式单例模式(线程不安全)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() { }
public static LazySingleton getInstance() { if (instance == null) { instance = new LazySingleton(); } return instance; } }
|
懒汉式单例模式(线程安全)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
public class SafeLazySingleton {
private static SafeLazySingleton instance;
private SafeLazySingleton() { }
public static synchronized SafeLazySingleton getInstance() { if (instance == null) { instance = new SafeLazySingleton(); } return instance; } }
|
饿汉式单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public class HungrySingleton {
private static final HungrySingleton instance = new HungrySingleton();
private HungrySingleton() { }
public static HungrySingleton getInstance() { return instance; } }
|
双重检查锁单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
public class DoubleCheckSingleton {
private static volatile DoubleCheckSingleton instance;
private DoubleCheckSingleton() { }
public static DoubleCheckSingleton getInstance() { if (instance == null) { synchronized (DoubleCheckSingleton.class) { if (instance == null) { instance = new DoubleCheckSingleton(); } } } return instance; } }
|
静态内部类单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton() { }
;
private static class Singleton { private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton(); }
public static StaticInnerClassSingleton getInstance() { return Singleton.INSTANCE; }
}
|
枚举单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
public enum EnumSingleton { INSTANCE; int value;
private EnumSingleton() { value = 1; System.out.println("INSTANCE now created!"); }
public int getValue() { return value; }
public void setValue(int value) { this.value = value; } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| package com.xiaofei.singleton;
import org.junit.Test;
public class SingletonTest {
@Test public void lazySingletonTest() { System.out.println("懒汉式单例模式(线程不安全)"); LazySingleton instance = LazySingleton.getInstance(); System.out.println(instance); System.out.println("懒汉式单例模式(线程不安全)\n");
}
@Test public void safeLazySingleton() { System.out.println("懒汉式单例模式(线程安全)"); SafeLazySingleton instance = SafeLazySingleton.getInstance(); System.out.println(instance); System.out.println("懒汉式单例模式(线程安全)\n"); }
@Test public void hungrySingleton() { System.out.println("饿汉式单例模式"); HungrySingleton instance = HungrySingleton.getInstance(); System.out.println(instance); System.out.println("饿汉式单例模式\n"); }
@Test public void doubleCheckSingleton() { System.out.println("双重检查锁单例模式"); DoubleCheckSingleton instance = DoubleCheckSingleton.getInstance(); System.out.println(instance); System.out.println("双重检查锁单例模式\n"); }
@Test public void staticInnerClassSingleton() { System.out.println("静态内部类单例模式"); StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance(); System.out.println(instance); System.out.println("静态内部类单例模式\n"); }
@Test public void enumSingleton() { System.out.println("枚举单例模式"); EnumSingleton singleton = EnumSingleton.INSTANCE; System.out.println(singleton.getValue()); singleton.setValue(2); System.out.println(singleton.getValue()); System.out.println("枚举单例模式\n");
} }
|
总结
- 懒汉式单例模式(线程不安全):
- 优点:实现简单,性能好。
- 缺点:线程不安全,需要在多线程环境下进行同步处理。
- 懒汉式单例模式(线程安全):
- 优点:线程安全,不需要额外的同步处理。
- 缺点:实现相对复杂,性能略差于饿汉式单例模式。
- 饿汉式单例模式:
- 优点:线程安全,性能好。
- 缺点:创建实例时会耗费一定的时间和资源。
- 双重检查锁单例模:
- 静态内部类单例模式:
- 枚举单例模式:
- 优点:线程安全,性能好。
- 缺点:枚举类型本身不能被修改,因此如果需要扩展功能则需要修改枚举类型。
综上所述,不同的单例模式适用于不同的场景。根据实际的需求选择合适的单例模式可以提高程序的效率,并保证单例实例的唯一性。