多线程下的单例模式

单例的实现

1.单线程下的Lazy实现

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

2.针对1的多线程阻塞实现

就是改进了check-then-act的原子性问题java

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

3.错误的双重加锁

public class Main {
    private static Main instance = null;
    
    private Main() {}
    
    public static Main getInstance() {
        if(null == instance) synchronized(Main.class) {
            if(null == instance) instance = new Main(); // 问题出如今初始化
        }
        return instance;
    }
}

注意可见性是正确的,错误在于初始化的重排序多线程

上一篇文章已经写了3个步骤,一个线程在判断第一个if的时候可能另外一个线程执行到第二个步骤就写入引用了,这时返回的是默认值线程

4.正确的双重加锁

既然重排序有问题那固然要volatilecode

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

5.静态内部类

利用class文件对于内部类的特性,实现上够简单排序

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

6.枚举类

仅访问Singleton自己不会使Singleton.INSTANCE初始化内存

public enum Singleton {
    INSTANCE;
    Singleton() {}
    public void doSomething() {}
}

public class Main {
    public static void main() {
        new Thread() {
            public void run() {
                Singleton.INSTANCE.doSomething();
            }
        }.start();
    }
    
}

懒汉?饿汉?

补充一下奇怪的术语:懒汉式、饿汉式get

其中懒汉式就是带Lazy加载的意思,好比一、2class

而饿汉式我并不太清楚字面上的意思。。应该是指内存宽裕吧。。就是static直接返回的那种,显然不如静态内部类序列化

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

破坏单例模式

1.除了enum和静态内部类,其它均可以被newInstance()拿到手

改进方法就是在构造方法建立保护null的判断引用

2.还有一种反序列化的破坏方式(若是你的单例须要序列化)。。

解决方法是重写readResolve()方法,使得它在方法内直接返回instance

相关文章
相关标签/搜索