单例模式

Posted lusaisai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式相关的知识,希望对你有一定的参考价值。

问题的由来:

为什么?

多个线程操作不同实例对象。多个线程要操作同一对象,要保证对象的唯一性

解决的问题:

实例化过程中只实例化一次

解决的思路

有一个实例化的过程(只有一次),产生实例化对象  new

提供返回实例对象的方法    getInstace()

单例模式的分类

饿汉式

饿汉就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例是已经存在的了
/**
* *是否 Lazy 初始化:否
* *是否多线程安全:是
* *实现难度:易
* *描述:这种方式比较常用,但容易产生垃圾对象。
* *优点:没有加锁,执行效率会提高。
* *缺点:类加载时就初始化,浪费内存。
* *它基于 classloder 机制避免了多线程的同步问题,
* * 不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,
* * 在单例模式中大多数都是调用 getInstance 方法,
* * 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,
* * 这时候初始化 instance 显然没有达到 lazy loading 的效果。
*
*/
public class HungerySingleton {
//加载的时候就产生的实例对象,ClassLoader
private byte[] data=new byte[1024];
private static HungerySingleton instance=new HungerySingleton();
private HungerySingleton(){
}

//返回实例对象
public static HungerySingleton getInstance(){
return instance;
}

public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
new Thread(()->{
System.out.println(HungerySingleton.getInstance());
}).start();
}
}
}

懒汉式

/**
*      *是否 Lazy 初始化:是
*      *是否多线程安全:否
*      *实现难度:易
*      *描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
*      *这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
*/
public class HungerySingleton {
//加载的时候就产生的实例对象,ClassLoader
private byte[] data=new byte[1024];
private static HungerySingleton instance=new HungerySingleton();
private HungerySingleton(){
}

//返回实例对象
public static HungerySingleton getInstance(){
return instance;
}

public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
new Thread(()->{
System.out.println(HungerySingleton.getInstance());
}).start();
}
}
}

线程不安全:不能保证实例对象的唯一性

技术图片

 

 

懒加载+性能好

懒汉式+同步方法

线程安全

懒加载

性能:synchronized  退化到了串行执行

public class HoonSynSingleton {
    private static HoonSynSingleton instance=null;
    private HoonSynSingleton(){
    }

    public synchronized static HoonSynSingleton getInstance(){
        if(null==instance)
            instance=new HoonSynSingleton();
        return instance;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                System.out.println(HoonSynSingleton.getInstance());
            }).start();
        }
    }
}
public class HoonSynSingletonDemo {
    private static HoonSynSingletonDemo instance=null;
    private HoonSynSingletonDemo(){
    }

    public  static HoonSynSingletonDemo getInstance(){
        if(null==instance)
            synchronized (HoonSynSingletonDemo.class){
                instance=new HoonSynSingletonDemo();
            }
        return instance;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                System.out.println(HoonSynSingletonDemo.getInstance());
            }).start();
        }
    }
}

DCL :Double-Check-Locking

public class DCL {
    Connection conn;
    Socket socket;
    private volatile static DCL instance=null;
    private DCL(){
    }

    public  static DCL getInstance(){
        if(null==instance)
            synchronized (DCL.class){
                if(null==instance)
                   if(null==instance)
                        instance=new DCL();
            }
        return instance;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                System.out.println(DCL.getInstance());
            }).start();
        }
    }
}

性能比较好

懒加载

线程的安全性

问题:因为指令重排一起空指针异常

技术图片

 

 

Holder

声明类的时候,成员变量中不声明实例变量,而放到内部静态类中,

public class HolderDemo {
    private HolderDemo(){

    }
    private static class Holder{
        private static HolderDemo instance=new HolderDemo();
    }
    //懒加载
    //synchronized
    //<init>
    public static HolderDemo getInstance(){
        return Holder.instance;
    }

    //广泛的一种单例模式
}
public class HoonSingleton {
    private static HoonSingleton instance=null;
    private HoonSingleton(){
    }

    public static HoonSingleton getInstance(){
        if(null==instance)
            instance=new HoonSingleton();
        return instance;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                System.out.println(HoonSingleton.getInstance());
            }).start();
        }
    }
}

枚举

public enum EnumSingleton {
    INSTANCE;
    public static EnumSingleton getInstance(){
        return INSTANCE;
    }
}

 

public enum EnumDemo {
    //常量,在加载的时候实例化一次,方法区
    A,B,C,D;
    int i=10;
    int j=20;
    public static void m1(){
        System.out.println("method");
    }

    public static void main(String[] args) {
        A.m1();
        B.m1();
        C.m1();
        D.m1();


        System.out.println(A.getClass().getName());
        System.out.println(B.getClass().getName());
        System.out.println(C.getClass().getName());
        System.out.println(D.getClass().getName());
    }
}

 

public class EnumSingletonDemo {
    private EnumSingletonDemo(){
    }
    //延迟加载
    private enum EnumHolder{
        INSTANCE;
        private  EnumSingletonDemo instance=null;
        EnumHolder(){
            instance=new EnumSingletonDemo();
        }
        private EnumSingletonDemo getInstance(){
            return instance;
        }
    }//懒加载
    public static EnumSingletonDemo  getInstance(){
        return EnumHolder.INSTANCE.instance;
    }

}

 

以上是关于单例模式的主要内容,如果未能解决你的问题,请参考以下文章

常用代码片段

性能比较好的单例写法

片段作为 Android 中的单例

单例片段或保存网页视图状态

你熟悉的设计模式都有哪些?写出单例模式的实现代码

单例模式以及静态代码块