设计模式之单例模式

简介

单例模式是一种经常使用的设计模式,该模式的特点是这个类只有一个实例,为什么要用单例模式呢?我的理解是为了一些全局变量便于管理,例如像一些经常需要创建销毁或创建时会消耗过多资源但又经常用到的对象,如果用单例模式实现,则只需要创建一次,之后用到时直接调用就可以(虽然感觉有些浪费空间,但是也节省了创建删除的开销),而且只有一个实例,方便管理。单例模式一般情况下有两种实现方式:饿汉式和懒汉式。我是这样理解的:饿汉式是指在类加载完成时就创建好实例(因为他饿,想早点吃......),懒汉式是指当需要的时候再实现(因为他懒,懒的早点创建......)。

基本实现思路

实现思路也很简单,只有两步:

1.私有化构造方法,这样在其他地方就不能实例化该类。

2.一个共有的静态方法创建该类的实例,当第一次调用该静态方法时会完成实例化,之后调用该方法时返回这个实例化对象,保证了从始至终只有一个实例。

写法

1.饿汉式:

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

这种写法简单容易,但是没有实现实时的效果,如果一直没用就造成资源浪费。

2.还是饿汉式.....:

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

这种也是饿汉式,只不过把实现放到了静态代码块中,和第一种没什么区别。

3.懒汉式单线程:

public class Singleton {
    private static Singleton singleton;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if(singleton == null)
            singleton = new Singleton();
        return singleton;
    }
}

这种写法实现了实时的效果,但是只适用于单线程下,如果同时有两个线程线程访问该方法就会创建两个实例,所以只适用于单线程。

4.懒汉式多线程:

class Singleton {
    private static Singleton singleton;
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance() {
        if(singleton == null) 
            singleton = new Singleton();
        return singleton;
    }
}

这种写法因为加了synchronized关键字,可用在多线程而且是线程安全的,但是效率低,不推荐使用。

5.懒汉式多线程:

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

这种写法比较恶心人,虽然有实现同步,但是没有实现线程同步,还是线程不安全的,如果同时有两个线程都进入该静态方法,一个经过判断语句进入同步代码块而另一个也通过判断语句时,等前一个线程完成释放对象锁另一个也会进入同步块,这样就会有两个实例,最好不要用。

6.双重检查:

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

这种在第5种写法基础上又加了一个判断语句的写法,实现了同步而且线程安全,可以使用。需要注意的是在私有成员变量上要加volatile修饰。

7.静态内部类:

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

这是一种高大上的写法,在类中写一个静态内部类,又像饿汉式又像懒汉式,说他像饿汉式是因为在内部类加载完成时完成了对该类的实例化,同时又实现了实时了加载,像是饿汉式和懒汉式的杂糅,同时静态内部类的内部属性在类加载时完成初始化,保证了线程安全也确保了只有一个实例,强烈推荐使用。

8.枚举,最高逼格的写法,是借助JDK1.5种添加的枚举来实现,然而我还不会......

原文地址:https://www.cnblogs.com/bigbrotherer/p/6212465.html