一、描述:
某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。
二、特点:
1.单例类只有一个实例对象
2.该单例对象必须由单例类自行创建
3.单例类对外提供一个访问该单例的全局访问点。
三、优点:
1.单例模式可以保证内存里只有一个实例,减少了内存的开销。
2.可以避免对自愿的多重占用。
3.单例模式设置全局访问点,可以优化和共享资源的访问。
四、应用场景:
1.需要频繁创建的一些类,使用单例可以降低系统的内存压力,减少GC。
2.某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用。
3.某些类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池,网络连接池等。
4.频繁访问数据库或文件的对象。
5.当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如Web中的配置对象、数据库的连接池等。
五、实现:
1.饿汉模式(类初始化时就创建,线程安全)
- public class HungaryTest {
- private static final HungaryTest hungaryTest = new HungaryTest();
-
- private HungaryTest() {
- }
-
- public static HungaryTest getHungaryTest() {
- return hungaryTest;
- }
- }
2.懒汉模式(需要的时候再创建,加volatile线程安全)
- public class SafetyLazy2Test {
- private static volatile SafetyLazy2Test safetyLazy2Test;
-
- private SafetyLazy2Test() {
- }
-
- public static synchronized SafetyLazy2Test getLazyTest() {
- if (safetyLazy2Test == null) {
- System.out.println("safetyLazy2Test是空");
- safetyLazy2Test = new SafetyLazy2Test();
- }
- System.out.println("safetyLazy2Test不是空");
- return safetyLazy2Test;
- }
- }
双重检测机制(DCL机制),同样可以实现线程安全
- public class SafetyLazyTest {
- private static volatile SafetyLazyTest safetyLazyTest;
-
- private SafetyLazyTest() {
- }
-
- public static SafetyLazyTest getLazyTest() {
- if (safetyLazyTest == null) {
- synchronized (SafetyLazyTest.class) {
- if (safetyLazyTest == null) {
- System.out.println("lazyTest是空");
- safetyLazyTest = new SafetyLazyTest();
- }
- }
- }
- System.out.println("lazyTest不是空");
- return safetyLazyTest;
- }
- }
线程测试:
- @Slf4j
- public class SafetyLazyThread extends Thread {
- @Override
- public void run() {
- super.run();
- log.info("safetyLazy:{}", SafetyLazyTest.getLazyTest().hashCode());
- log.info("safetyLazy2:{}", SafetyLazy2Test.getLazyTest().hashCode());
- }
- }
-
- public class ThreadTest {
- public static void main(String[] args) {
- safetyThreadTest();
- }
-
- private static void safetyThreadTest() {
- SafetyLazyThread t1 = new SafetyLazyThread();
- SafetyLazyThread t2 = new SafetyLazyThread();
- SafetyLazyThread t3 = new SafetyLazyThread();
- SafetyLazyThread t4 = new SafetyLazyThread();
- t1.start();
- t2.start();
- t3.start();
- t4.start();
- }
- }
运行结果:
- lazyTest是空
- lazyTest不是空
- lazyTest不是空
- lazyTest不是空
- lazyTest不是空
- 10:55:32.381 [Thread-2] INFO com.my.project.designmode.singletoninstance.SafetyLazyThread - safetyLazy:1149747804
- 10:55:32.381 [Thread-1] INFO com.my.project.designmode.singletoninstance.SafetyLazyThread - safetyLazy:1149747804
- 10:55:32.381 [Thread-0] INFO com.my.project.designmode.singletoninstance.SafetyLazyThread - safetyLazy:1149747804
- 10:55:32.381 [Thread-3] INFO com.my.project.designmode.singletoninstance.SafetyLazyThread - safetyLazy:1149747804
- safetyLazy2Test是空
- safetyLazy2Test不是空
- safetyLazy2Test不是空
- safetyLazy2Test不是空
- 10:55:32.387 [Thread-2] INFO com.my.project.designmode.singletoninstance.SafetyLazyThread - safetyLazy2:1682859985
- 10:55:32.387 [Thread-0] INFO com.my.project.designmode.singletoninstance.SafetyLazyThread - safetyLazy2:1682859985
- 10:55:32.387 [Thread-1] INFO com.my.project.designmode.singletoninstance.SafetyLazyThread - safetyLazy2:1682859985
- safetyLazy2Test不是空
- 10:55:32.387 [Thread-3] INFO com.my.project.designmode.singletoninstance.SafetyLazyThread - safetyLazy2:1682859985
3.静态内部类(线程安全,推荐使用。调用时才会创建。)
- @Slf4j
- public class StaticTest {
- private static class StaticSingletonTest {
- private static final StaticTest staticTest = new StaticTest();
- }
-
- private StaticTest() {
- }
-
- public static StaticTest getInstance() {
- return StaticSingletonTest.staticTest;
- }
- }
4.枚举模式
- public enum EnumSingleton {
- INSTANCE;
- public EnumSingleton getInstance(){
- return INSTANCE;
- }
- }