设计模式-单例模式

119 阅读2分钟

单例模式

顾名思义,使这个类在全局只有一个实例,单例模式的写法很多,讨论一下这些写法,spring也有个单例的注解,它是怎么实现的呢?

网上的多种实现方式

懒汉式一

public class TestLazyMan{
    public static void main(String[] args){
        new Thread(new TestMutiType()).start();
        new Thread(new TestMutiType()).start();
    }
}

class TestMutiType implements Runnable{

    @Override
    public void run() {
        LazyMan instance = LazyMan.getInstance();
        System.out.println(instance);
    }
}


class LazyMan {
    private static LazyMan lazyMan;
    private LazyMan(){

    }

    public static LazyMan getInstance(){
        if(lazyMan == null){
            lazyMan = new LazyMan();
        }
        return lazyMan;
    }
}

print:
/*这里的结果 有时是一样的,有时不一样*/
designpatterns.singleton.LazyMan@5bdbaa31
designpatterns.singleton.LazyMan@7dfa4e7

这种实现方式有线程安全问题,多线程情况下不要用

懒汉式二

public class TestLazyMan{
    public static void main(String[] args){
        new Thread(new TestMutiType()).start();
        new Thread(new TestMutiType()).start();
    }
}

class TestMutiType implements Runnable{

    @Override
    public void run() {
        LazyMan instance = LazyMan.getInstance();
        System.out.println(instance);
    }
}


class LazyMan {
    private static LazyMan lazyMan;
    private LazyMan(){

    }

    public static synchronized LazyMan getInstance(){
        if(lazyMan == null){
            lazyMan = new LazyMan();
        }
        return lazyMan;
    }
}

print:
designpatterns.singleton.LazyMan@2b282c31
designpatterns.singleton.LazyMan@2b282c31

加上synchronized保证了线程安全

饿汉式

public class TestHungryMan {
    public static void main(String[] args){
        new Thread(new MultiType()).start();
        new Thread(new MultiType()).start();
    }
}

class MultiType implements Runnable{
    @Override
    public void run() {
        HungryMan instance = HungryMan.getInstance();
        System.out.println(instance);
    }
}

class HungryMan{
    private static HungryMan hungryMan = new HungryMan();
    private HungryMan(){}
    public static HungryMan getInstance(){
        return hungryMan;
    }
}

print:
designpatterns.singleton.HungryMan@4336eeed
designpatterns.singleton.HungryMan@4336eeed

看起来不错,但我觉得这种实现实际上是在投机取巧,当我们需要一个实例时,也许像要在它初始化去做一些事情,如果将他放到类加载时来做单例,那它还可以做一些我们的事情吗,是不是所有的事情都要被牵扯到类加载时去做。

双重校验锁

public class TestDoubleCheck {
    public static void main(String[] args){
        new Thread(new MultiDoubleCheck()).start();
        new Thread(new MultiDoubleCheck()).start();
    }
}

class MultiDoubleCheck implements Runnable{

    @Override
    public void run() {
        DoubleCheck instance = DoubleCheck.getInstance();
        System.out.println(instance);
    }
}

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

print:
designpatterns.singleton.DoubleCheck@782b1823
designpatterns.singleton.DoubleCheck@782b1823

有一个需要注意的点:实例加了volatile关键字,如果不加这个关键字会发生什么呢?

如果编译器初始化时重排序了,那么有可能当这个单例还没有初始化完成,就被另一个线程拿去用了

静态内部类式

public class TestStaticInner {
    public static void main(String[] args){
        new Thread(new TestMultiStaticInner()).start();
        new Thread(new TestMultiStaticInner()).start();
    }
}

class TestMultiStaticInner implements Runnable{

    @Override
    public void run() {
        StaticInner instance = StaticInner.getInstance();
        System.out.println(instance);
    }
}

class StaticInner{
    private static class StaticInnerHolder{
        private static final StaticInner instance = new StaticInner();
    }
    private StaticInner(){}
    public static StaticInner getInstance(){
        return StaticInnerHolder.instance;
    }
}

好,项目里目前用的都是这种,既不主动,又不被动

spring的实现方式

挖个坑先,以后再填