单例模式

单例模式初衷是为了使资源能够共享,只需要赋值或初始化一次,大家都能够重复利用。

饿汉模式: 在类加载的时候就立即初始化并且创建单例对象。优点是没有加任何锁,执行效率高,绝对线程安全。在用户体验上来说比懒汉模式更好,缺点是一定程度上浪费内存。

懒汉模式: 在需要使用的时候才初始化,不浪费资源,但是线程不安全。

单例模式的七种写法:

1. 饿汉模式,线程安全

public static class Singleton {
    private final static Singleton INSTANCE = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return INSTANCE;
    }
 }

2.懒汉模式,线程不安全

 public static class Singleton1 {
    private static Singleton2 instance = null;
    private Singleton2() {}
    public static Singleton2 getInstance() {
        if (instance == null) {
            instance = new Singleton2();
        }
        return instance;
    }
 }

3.懒汉模式,线程安全,多线程环境下效率不高

public static class Singleton2 {
    private static Singleton2 instance = null;
    private Singleton2() {}
    public static synchronized Singleton2 getInstance() {
        if (instance == null) {
            instance = new Singleton3();
        }
        return instance;
    }
 }

4. 懒汉模式,变种,线程安全

 public static class Singleton3 {
    private static Singleton3 instance = null;
    
    static {
        instance = new Singleton3();
    }
    private Singleton3() {}
    public static Singleton3 getInstance() {
        return instance;
    }
 }

5. 使用静态内部类,线程安全【推荐】 *内部类在被主类调用的时候才会被加载,这样兼顾了资源问题和线程安全问题*

public static class Singleton4 {
    private final static class SingleHolder {
        private static final Singleton4 INSTANCE = new Singleton4();
    }
    private Singleton4(){}
    public final static Singleton4 getInstance() {
        return Singleton4Holder.INSTANCE;
    }
 }

 

6. 使用枚举,线程安全【推荐】

 public enum class Singleton5 {
    INSTANCE;
 }

7. 双重锁

public static class Singleton6 {
    private volatile static Singleton6 instance = null;
    private Singleton6(){}
    
    public static Singleton6 getInstance() {
        if(instance == null) {
            sychronized (Singleton6.class) {
                if (instance == null) {
                    instance = new Singleton6();
                }
            }
        }   
    }
    return instance;
 }

 

PS:

  1. 防止反射攻击: 加flag:

public static class Singleton6 {
    private volatile static Singleton6 instance = null;
    private boolean flag = false;
    private Singleton6(){   
synchronized(Singleton6.class) {
if (flag == false) { flag = !flag; } else { return new RunTimeException("遭遇反射攻击"); }
} }
public static Singleton6 getInstance() { if(instance == null) { sychronized (Singleton6.class) { if (instance == null) { instance = new Singleton6(); } } } } return instance; }

 

  2. 防止序列化造成两个实例。写readResolve方法。

public static class Singleton {
    private final static Singleton INSTANCE = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return INSTANCE;
    }
    public Object readResolve() {
        return INSTANCE;
    }
 } 

 

     3. 附上一个测试实例安全测试方法。使用CountDownLaunch。

 public static void main(String[] args) {
        int count = 200;
        CountDownLatch latch = new CountDownLatch(count);

        for (int i = 0; i<count; i++) {
            new Thread(){
                @Override
                public void run(){
                    try {
                        latch.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Object obj = Factory.getInstance();
                    System.out.println(System.currentTimeMillis()+ ":" + obj);
                }
            }.start();
            latch.countDown();
        }
        
        
    }

 

应用场景:

Spring的IOC容器。

 

 

posted @ 2018-10-26 14:58  天才小彩笔i  阅读(105)  评论(0编辑  收藏  举报