简单说几句
本文首发公众号【一名打字员】
说起这个单例,简直是人名中的张伟、代码圈中的八阿哥,已经被广泛的所使用。但是你真的会单例么?来我们拭目以待吧。
各种写法
单例的写法有很多,相信大家都知道的应该是饿汉与饱汉式。
饿汉式
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
所谓饿汉式,就是饿了太久了,上来就开始吃。这种方式在这个类加载的时候就创建了实例,方便我们可以在其他地方直接使用,但是缺点就是不管有没有用到这个类的方法,他都会创建,会造成不必要的开销。
饱汉式
public class Singleton{
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
if(null == instance){
instance = new Singleton();
}
return instance;
}
}
显而易见,饱汉式与饿汉式刚好对立,一个饿太久了,上来就吃,一个没吃就吃、吃饱了就不吃了。在需要获取实例的时候才回去创建新的对象,在我们使用频率比较少的时候以及创建一次实例需要消耗比较大的资源时,推荐使用这种方式。
双重检查锁
但是,与饿汉式不会存在多线程创建多个实例不同的是,饱汉式无法保证线程安全,可能会导致多个线程使用创建多个实例,机智的我们肯定会加上一个同步锁,但是这样效率肯定就不行了。因为每次调用生成实例的话都需要在同步那里进行等待,所以,就出现了双重检查锁。
public class Singleton{
private static volatile Singleton singleton = null;
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null){
synchronized (Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
静态内部类
先贴上代码:
public class Singleton {
private static class Holder {
private static Singleton singleton = new Singleton();
}
private Singleton(){}
public static Singleton getInstance(){
return Holder.singleton;
}
}
这样的方法,既保证了线程的安全,也能按需加载,貌似看起来是最优的方法了。
枚举
相信很多打字员都应该知道还有一种很优雅的写法,就是枚举。
public enum Singleton {
INSTANCE;
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
这种方法本打字员是在Effective Java中了解到了,之前还真的没了解过,而且在书中推荐的就是这种写法,原因是Prevent reflection forcibly call the constructor,意思差不多就是防止反射强行调用构造器吧。
写在最后
本打字员觉得,单例模式实在是所有模式中用情最专一的模式了,知道为什么吗,因为使用了它以后,你一生只能而且只会拥有一个对象了!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。