zoukankan      html  css  js  c++  java
  • 设计模式 | 单例模式(singleton)

    定义:

    保证一个类仅有一个实例,并提供一个访问它的全局访问点。

    结构:(书中图,侵删)

    结构超简单。就在你想控制实例数的类上操作即可。
    1.定义一个static的对象引用
    2.私有化构造方法
    3.提供一个获取实例的方法(static的)
     

    实例:

    这又是一个在面试中频繁出现的设计模式,我至今不知道为什么大家那么偏爱这个模式。
    而且基本上都是让你现场写一个单例模式的例子,基于这个很现实的原因,这个模式也好好好掌握。
    我这里就不举生活中的例子了,直接上代码。
     
    单例模式又分为两种形式:
    一、饿汉式:在类加载是就初始化实例。
    二、懒汉式:在第一次调用的时候,才初始化实例。
     
    饿汉式:
    package designpattern.singleton;
    
    public class HungrySingleton {
        private static HungrySingleton instance = new HungrySingleton();// 静态初始化
    
        private HungrySingleton() {// 私有化构造方法
        }
    
        public static HungrySingleton GetInstance() {// 获取实例,static的
            return instance;
        }
    }
    懒汉式:
    package designpattern.singleton;
    
    public class LazySingleton {
        private static LazySingleton instance;
    
        private LazySingleton() {// 私有化构造方法
    
        }
    
        public static LazySingleton getInstance() {// 获取实例,static的
            if (instance == null) {
                instance = new LazySingleton();// 方法中创造实例
            }
            return instance;
        }
    }
    但是,如果是在多线程的情况下,可能会造成创造出两个实例的情况,可以考虑在getInstance方法上加上synchronized修饰:
    package designpattern.singleton;
    
    public class LazySingleton2 {
        private static LazySingleton2 instance;
    
        private LazySingleton2() {
    
        }
    
        public static synchronized LazySingleton2 getInstance() {// synchronized 修饰
            if (instance == null) {
                instance = new LazySingleton2();
            }
            return instance;
        }
    }
    这个可以进一步优化,只让线程在还没有实例化的情况下加锁:
    package designpattern.singleton;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class LazySingleton3 {
        private static LazySingleton3 instance;
        private static Lock lock = new ReentrantLock();
    
        private LazySingleton3() {
    
        }
    
        public static synchronized LazySingleton3 getInstance() {
            try {
                if (instance == null) {
                    lock.lock();
                    if (instance == null) {// 有必要再次判断,不然还是存在线程安全问题
                        instance = new LazySingleton3();
                    }
                    lock.unlock();
                }
            } finally {// 保证锁被释放
                lock.unlock();
            }
            return instance;
        }
    }

    总结:

    饿汉式,在类加载是就初始化实例,要提前占用系统资源,但是不用考虑多线程访问可能造成的创建多个实例的问题。
    懒汉式,在第一次调用的时候,才初始化实例,不用提前占用系统资源,但是需要考虑到多线程访问的问题。
    这个模式在所有需要控制实例数的情况下都能使用,最常见的两个例子,就是数据库连接池和线程池。
    以下原因引用自https://www.cnblogs.com/gmq-sh/p/5948379.html《单例模式的常见应用场景》:
    数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。
     
  • 相关阅读:
    Ubuntu终端Terminal常用快捷键
    继承(一)
    c语言中动态数组的建立
    指针的一些小的知识点
    什么是内存地址
    组合(composition)与继承(inheritance)
    重载new和delete
    不要轻易delete void*指针,这样会隐藏比较多的错误。
    内存管理运算符new delete与内存管理函数malloc free的区别——已经他们对对象创建的过程。
    自动类型转换之全局重载运算符与成员重载运算符
  • 原文地址:https://www.cnblogs.com/imoqian/p/10986927.html
Copyright © 2011-2022 走看看