Java 设计模式——单例模式 理论代码相结合

 1、前言

概念:

单例模式,属于建立类型的一种经常使用的软件设计模式。经过单例模式的方法建立的类在当前进程中只有一个实例(根据须要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例)--来自百度百科数据库

应用:

单例模式可让咱们只建立一个对象从而避免了频繁建立对象致使的内存消耗和垃圾回收。设计模式

单例模式只容许建立一个对象,所以节省内存,加快对象访问速度,所以对象须要被公用的场合适合使用,如多个模块使用同一个数据源链接对象等等。如:安全

  1. 须要频繁实例化而后销毁的对象。
  2. 建立对象时耗时过多或者耗资源过多,但又常常用到的对象。
  3. 有状态的工具类对象。
  4. 频繁访问数据库或文件的对象。

项目中的具体应用:多线程

  1. 封装一些经常使用的工具类,保证整个应用经常使用的数据统一
  2. 保存一些共享数据在内存中,其余类随时能够读取。

实现单例模式的原则和过程:

  1. 单例模式:确保一个类只有一个实例,自行实例化并向系统提供这个实例
  2. 单例模式分类:饿单例模式(类加载时实例化一个对象给本身的引用),懒单例模式(调用取得实例的方法如getInstance时才会实例化对象)
  3. 单例模式要素: a.私有构造方法 b.私有静态引用指向本身实例 c.以本身实例为返回值的公有静态方法

方式:

单例模式有八种方式:ide

  1. 饿汉式(静态常量)
  2. 饿汉式(静态代码块)
  3. 懒汉式(线程不安全方式)
  4. 懒汉式(线程安全,同步方法)
  5. 懒汉式(线程不安全,同步代码块)
  6. 懒汉式(双重检查)
  7. 懒汉式(静态内部类)
  8. 枚举实现
2、单例模式代码实现及分析

2.一、饿汉式(静态常量)

代码实现:工具

/**
 * 单例模式
 * @Author: crush
 * @Date: 2021-08-06 9:14
 * version 1.0
 */
public class SingletonTest1 {
    public static void main(String[] args) {
        // 获取两次,看获取到的对象 确实是单例的吗
        Singleton singleton = Singleton.getInstance();
        Singleton singleton1 = Singleton.getInstance();

        System.out.println(singleton == singleton1);

        System.out.println("singleton  hashcode:"+singleton.hashCode());
        System.out.println("singleton1 hashcode:"+singleton1.hashCode());
        /**
         * 输出:
         * true
         * singleton  hashcode:24324022
         * singleton1 hashcode:24324022
         */
    }
}

/**
 *  一、饿汉式(静态常量)代码实现
 */
class Singleton{
    /*** 构造器私有化*/
    private Singleton(){};
    
    /** * 在类的内部建立一个对象实例 随当前类加载而加载 没有线程安全问题。 */
    private final static Singleton INSTANCE=new Singleton();
    
    /*** 再提供一个 公有的方法来返回这个静态常量*/
    public static Singleton getInstance(){
        return INSTANCE;
    }
}

结论及优缺测试

  1. 优势:饿汉式(静态常量方式)它不用担忧线程安全问题,它自己就是在类的装载的时候完成实例化的。spa

  2. 缺点:可是缺点也在这个地方,无论用不用,只要类装载了,那么他就会直接完成实例化,不能达到懒加载的效果,若是你从始至终都没有使用过这个类,那么就会形成内存的浪费。线程

    注意:你可能会想类都已经加载了,为何我还会不用到呢?设计

    在单例模式中大都调用getInstance方法,getInstance这个静态方法可让类加载,那么一样的道理,若是这个类中还有其余的静态方法,你调用它的时候,一样会使类进行装载。

  3. 小结:这种单例方式,其实仍是能够用的,至少不用担忧线程同步问题,那种使用特别频繁的类用这种方式仍是没啥问题的,除了可能会致使内存浪费

2.二、饿汉式(静态代码块)

/**
 * 单例模式 2
 *
 * @Author: crush
 * @Date: 2021-08-06 9:14
 * version 1.0
 */
public class SingletonTest1 {
    public static void main(String[] args) {
        // 咱们去拿两次,看获取到的对象 确实是单例的吗
        Singleton singleton = Singleton.getInstance();
        Singleton singleton1 = Singleton.getInstance();

        System.out.println(singleton == singleton1);

        System.out.println("singleton  hashcode:" + singleton.hashCode());
        System.out.println("singleton1 hashcode:" + singleton1.hashCode());
        /**
         * 输出:
         * true
         * singleton  hashcode:24324022
         * singleton1 hashcode:24324022
         */
    }
}

/**
 * 一、饿汉式(静态代码块)代码实现
 */
class Singleton {

    /** * 构造器私有化 */
    private Singleton() {
    }
    /** * 在类的内部建立一个对象实例 随当前类加载而加载 没有线程安全问题。*/
    private static Singleton singleton;

    static {
        //改成在静态代码块中 建立单例对象
        singleton = new Singleton();
    }

    /** * 再提供一个 公有的方法来返回这个静态常量  */
    public static Singleton getInstance() {
        return singleton;
    }
}

结论:这种方式其实和第一种很是相似,只是将类的实例化过程放进静态代码块而已。优缺点同饿汉式(静态常量)。

2.三、懒汉式(线程不安全)

/**
 * 单例模式
 *
 * @Author: crush
 * @Date: 2021-08-06 9:14
 * version 1.0
 */
public class SingletonTest3 {
    public static void main(String[] args) {

        //懒汉式  线程不安全方式,适合单线程使用
        //===========单线程下是安全的 ,测试代码和第一种同样===========
        // =========模拟多线程下=============
        Runnable runnable = new Runnable(){
            @Override
            public void run() {
                Singleton instance = Singleton.getInstance();
                System.out.println(instance.hashCode());
            }
        };

        Runnable runnable2 = new Runnable(){
            @Override
            public void run() {
                Singleton instance1 = Singleton.getInstance();
                System.out.println(instance1.hashCode());
            }
        };
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable2);
        thread1.start();
        thread2.start();
        /**
         * 结果并不惟一,
         * 可能会出现相同,也有可能不一样,多测几回,就能发现是线程不安全的。
         * 94433
         * 21648409
         */
    }
}

/**
 * 懒汉式 线程不安全方式
 */
class Singleton {

    /*** 构造器私有化*/
    private Singleton() {}
    
    /*** 在类的内部建立一个对象实例 随当前类加载而加载 没有线程安全问题。*/
    private static Singleton singleton;

    /**
     * 提供一个公有的方法
     * 当使用到这个方法时,才去建立singleton
     */
    public static Singleton getInstance() {
        if(singleton==null){
            // 经过在这里堵赛的方式来模拟多线程
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            singleton= new Singleton();
        }
        return singleton;
    }
}

结论及优缺:

  1. 优势:起到了懒加载的效果
  2. 缺点:线程不安全,若是在多线程下,第一个线程进入到if(singleton==null)下,但还将来的及执行,第二个线程就紧随而来也进入了if(singleton==null)下,那么就会建立多个实例。就不是单例模式了。
  3. 建议:开发不要使用这种方式,线程安全问题不能解决,就是
相关文章
相关标签/搜索