一文搞懂java单例模式

单例模式作为java设计模式里最常用的一种设计模式之一,在我们日常的开发中大量被使用,现在我想从理论到实践重新梳理一下这个知识点,帮助基础薄弱的自己进一步加深理解。

什么是单例模式(Singleton)

“单例”,顾名思义就是只有一个类的实例

单:唯一

例:实例

 

单例设计模式:确保某一个类只有一个实例,自行实例化并向整个系统提供这个实例,同时也提供全局访问的方法以供调用。

 

 

要点

  1. 确保一个类只能有一个实例
  2. 必须是自行创建这个实例,避免外部创建实例或者被子类继承从而创建额外实例
  3. 必须自行的向整个系统提供这个实例

 

从代码实现角度来看:

  1. 将单例类的构造函数私有化,这样外部代码就无法直接用new来实例化该对象
  2. 定义一个该类的静态私有对象
  3. 提供一个静态的公共方法用于创建;获取类的静态私有对象

 

有多种实现方式,主要分为以下两大类:

  1. 饿汉式:

 

优点:直接创建对象,不存在线程安全问题,在类创建好的同时对象生成,调用获得对象实例的方法反应速度快,代码简洁。

 

缺点:资源利用效率低,用不用的都创建了;系统启动加载时间可能会比较长

 

  1. 懒汉式:

 

优点:延迟加载对象,资源利用效率高

 

缺点:代码相对复杂一点;线程不安全,要加锁控制,这就会导致性能受到影响;第一次加载类的对象反应稍慢

饿汉式代码demo

package com.java_foundation.singleton;

/**
 * @program: java_foundation
 * @description:
 * 饿汉式:直接创建对象,不管是否使用该对象都会创建
 * 特点:1)构造器私有化
 *      2)自行创建,并用静态变量保存
 *      3)向外部提供这个实例
 *      4)可以使用final修饰,强调这是一个单例
 * @author: xiongbangwen <Email>[email protected]</Email>
 * @create: 2020-05-30 20:35
 **/
public class Singleton_1 {
    public static final Singleton_1 INSTANCE = new Singleton_1();
    private Singleton_1(){
        System.out.println("单例模式");
    }
}

枚举式单例

package com.java_foundation.singleton;

/**
 * @program: java_foundation
 * @description: 枚举
 * 表示该类型的对象是有限的几个
 * 当限定为一个时,就变成了单例
 * 重写了toString()方法,一般返回的是常量名字
 * @author: xiongbangwen <Email>[email protected]</Email>
 * @create: 2020-05-30 20:43
 **/
public enum Singleton_2 {
    INSTANCE;
}

懒汉式demo(线程不安全)

package com.java_foundation.singleton;

import java.io.IOException;
import java.util.Properties;

/**
 * @program: java_foundation
 * @description: 静态代码块的单例
 * @author: xiongbangwen <Email>[email protected]</Email>
 * @create: 2020-05-30 20:52
 **/
public class Singleton_3 {

    public static final Singleton_3 INSTANCE;
    private String info;

    static {
        try {
            Properties pro = new Properties();

            pro.load(Singleton_3.class.getClassLoader().getResourceAsStream("singleton.properties"));

            INSTANCE = new Singleton_3(pro.getProperty("info"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    private Singleton_3(String info){
        this.info = info;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Singleton_3{" +
                "info='" + info + '\'' +
                '}';
    }
}

懒汉式demo(加锁版)

package com.java_foundation.singleton;

/**
 * @program: java_foundation
 * @description: 懒汉式:延迟创建这个实例对象,创建一次就不再创建,有线程安全问题
 * 1)构造器私有化
 * 2)用一个静态变量保存这个唯一的实例
 * 3)提供一个静态方法去获取这个实例对象
 * @author: xiongbangwen <Email>[email protected]</Email>
 * @create: 2020-05-30 21:25
 **/
public class Singleton_5 {
    private static Singleton_5 instance;
    private Singleton_5(){

    }
    public static Singleton_5 getInstance(){
        if(instance == null) {
            synchronized (Singleton_5.class) {
                if (instance == null) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    instance = new Singleton_5();
                }
            }
        }
        return instance;
    }
}

懒汉式优化,用静态内部类实现

package com.java_foundation.singleton;

/**
 * @program: java_foundation
 * @description: 在内部类被加载时和初始化,才创建INSTANCE对象
 * 静态内部类不会自动随着外部类的加载和初始化而初始化,它是要单独去加载和初始化的
 * 因为是在内部类加载和初始化时创建的,因此线程是安全的
 * @author: xiongbangwen <Email>[email protected]</Email>
 * @create: 2020-05-30 21:42
 **/
public class Singleton_6 {
    private Singleton_6(){

    }
    private static class Inner{
        private static final Singleton_6 INSTANCE = new Singleton_6();
    }
    public static Singleton_6 getInstance(){
        return Inner.INSTANCE;
    }
}

Test测试类

package com.java_foundation.singleton;

import java.util.concurrent.*;

/**
 * @program: java_foundation
 * @description: 测试
 * @author: xiongbangwen <Email>[email protected]</Email>
 * @create: 2020-05-30 20:41
 **/
public class Test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        Singleton_1 s1 = Singleton_1.INSTANCE;
//        System.out.println(s1);
//        Singleton_2 s2 = Singleton_2.INSTANCE;
//        System.out.println(s2);
//        Singleton_3 s3 = Singleton_3.INSTANCE;
//        System.out.println(s3);
//        Singleton_4 s4 = Singleton_4.getInstance();
//        Singleton_4 s5 = Singleton_4.getInstance();
//        System.out.println(s4);
//        System.out.println(s5);
        //懒汉式单线程没有问题
//        Callable<Singleton_4> c = new Callable<Singleton_4>() {
//            @Override
//            public Singleton_4 call() throws Exception {
//                return Singleton_4.getInstance();
//            }
//        };
//        ExecutorService es = Executors.newFixedThreadPool(2);
//        Future<Singleton_4> f1 = es.submit(c);
//        Future<Singleton_4> f2 = es.submit(c);
//        Singleton_4 s6 = f1.get();
//        Singleton_4 s7 = f2.get();
//        System.out.println(s6);
//        System.out.println(s7);
//        System.out.println(s6==s7);
        //加锁
//        Callable<Singleton_5> c = new Callable<Singleton_5>() {
//            @Override
//            public Singleton_5 call() throws Exception {
//                return Singleton_5.getInstance();
//            }
//        };
//        ExecutorService es = Executors.newFixedThreadPool(2);
//        Future<Singleton_5> f1 = es.submit(c);
//        Future<Singleton_5> f2 = es.submit(c);
//        Singleton_5 s6 = f1.get();
//        Singleton_5 s7 = f2.get();
//        System.out.println(s6);
//        System.out.println(s7);
//        System.out.println(s6==s7);
        //静态内部类形式
        Callable<Singleton_6> c = new Callable<Singleton_6>() {
            @Override
            public Singleton_6 call() throws Exception {
                return Singleton_6.getInstance();
            }
        };
        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<Singleton_6> f1 = es.submit(c);
        Future<Singleton_6> f2 = es.submit(c);
        Singleton_6 s6 = f1.get();
        Singleton_6 s7 = f2.get();
        System.out.println(s6);
        System.out.println(s7);
        System.out.println(s6==s7);
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章