一、什么是单例
Singleton是指只实例化一次的类,系统中只存在一个该类的实例,就好像一个国家只能同时存在一个总统,多了得乱啊。比如说美国总统这个类在上一个运行期实例化出了巴马总统。而在下一个运行期又重新实例化出一个特朗普总统。
二、创建单例的三种方式
(1)懒汉式单例,顾名思义,这个单例比较懒,我不来调用getInstance()方法,它就不会进行实例化。
懒汉式单例1.0
public class Singleton
{
// 懒汉式单例,不马上实例化而是等到调用getInstance方法再进行实例化
private static Singleton singleton = null;
public static Singleton getInstance()
{
if (singleton == null)
{
singleton = new Singleton();
}
return singleton;
}
//构造器必须私有,防止进行多次实例化
private Singleton()
{
}
}
在懒汉式1.0中呢存在一个问题,那就是线程安全,如果有并发环境下有多个线程同时进行if(singleton==null)检查,然后同时检查通过并创建出多个对象,那么就不是单例了,就好像美国佬同时选出了几个总统,这不得乱了套。我们得对选总统这件事控制一下,确保一个任期内只能选出一位总统。
懒汉式单例2.0
public class Singleton
{
// 懒汉式单例,不马上实例化而是等到调用getInstance方法再进行实例化
private static Singleton singleton = null;
public static Singleton getInstance()
{
if (singleton == null)
{
synchronized (Singleton.class)
{
singleton = new Singleton();
}
}
return singleton;
}
private Singleton()
{
}
}
现在呢我们把singleton=new Singleton(),这个代码块给锁起来了,那是不是很安全了呢,看起来好像是哈,现在不能同时产生总统了,但是呢!稍微有点多线程基础的兄弟都知道,我们有个很重要的没同步啊!那就是if(singleton==null),假如多个线程同时通过这个判断,然后基于一个对象的锁只能同时被一个线程拥有,现在呢singleton=new Singleton()由原来多个对象并行变成串行了。嘿嘿嘿,按照基本法我们现在不同时选出总统了,但是我们可以排着队来,你选了该我们选。最终还是会选出多个总统,还是乱套。看到这里,解决方案已经很明显了!
懒汉式单例3.0
private static Singleton singleton = null;
public static Singleton getInstance()
{
synchronized (Singleton.class)
{
if (singleton == null)
{
singleton = new Singleton();
}
}
return singleton;
}
这次确实可以了,但是呢每次进入getInstance方法都要同步,是很极端的行为,是会影响性能的。
懒汉式4.0
public static Singleton getInstance()
{
if (singleton == null)
{
synchronized (Singleton.class)
{
if (singleton == null)
{
singleton = new Singleton();
}
}
}
return singleton;
}
现在呢加入了一个双重检查!这样防止了每次进入都必须同步,又保证了只产生一个实例对象!
(2)饿汉式单例
饿汉式单例:我很饿,我进来就要吃东西,东西必须提前准备好!哈哈,这可能就是为什么叫饿汉式的原因吧,瞎掰的!饿汉式单例指加载类时就实例化该类的对象,而不是等到调用getInstance方法再去实例化,因为单例的实例被声明成 static 和 final 变量了,在第一次加载类到内存中时就会初始化,所以创建实例本身是线程安全的。
public class Singleton
{
// 饿汉式单例,马上实例化而不是等到调用getInstance方法再进行实例化
private static final Singleton singleton = new Singleton();
public static Singleton getInstance()
{
return singleton;
}
private Singleton()
{
}
}
(3)枚举类创建单例
这也是Effective Java中推荐的方法,这种方法更加简洁,无偿提供了序列化机制,线程安全,绝对防止多次实例化,已经成为实现Singleton的最佳方法。
public enum Singleton
{
SINGLETON;
}
直接通过Singleton.SINGLETON进行访问。
三、结语
哈哈,本人也是16年应届生,记得前面做华为笔试题遇到过,当时可耻的在构造器中写了返回单例,哈哈,后面还舔着脸问是不是错得很离谱,无奈面试官叫我回来百度!最近看Effective Java结合网上经典讲解理解了一番。顺便记录下。