下面的单例实现都是线程安全的。
一、
package practise;
public class Singleton1
{
public static final Singleton1 INSTANCE = new Singleton1();
private Singleton1(){}
}
这是比较简单的单例模式,在类加载初始化的时候就实例化INSTANCE,所以可能在没有使用INSTANCE的时候就实例化,造成资源浪费。
二、
package practise;
public class Singleton2
{
private static final Singleton2 INSTANCE = new Singleton2();
private Singleton2(){}
public static Singleton2 getInstance()
{
return INSTANCE;
}
}
这个实现也是类加载就实例化INSTANCE,但是提供了一个静态工厂方法来获取实例,优点是提供了灵活性,以后更改getInstance的实现比较方便。
三、
package practise;
public class Singleton3
{
private static volatile Singleton3 INSTANCE;
private Singleton3(){}
public static Singleton3 getInstance()
{
if(INSTANCE == null)
{
synchronized (INSTANCE)
{
if(INSTANCE == null)
INSTANCE = new Singleton3();
}
}
return INSTANCE;
}
}
这个单例是延迟实例化INSTANCE,或者叫做懒汉方式,只有在第一次用到INSTANCE的时候才实例化,主要是为了节约内存。这里需要注意的是double check,双重确定INSTANCE == null,不然也可以将synchronized 放在getInstance方法上。不过绝大部分时候是不需要同步的,所以double check的效率要高很多。
四、
package practise;
public class Singleton4
{
private static class Inner
{
public static final Singleton4 INSTANCE = new Singleton4();
}
private Singleton4(){}
public static Singleton4 getInstance()
{
return Inner.INSTANCE;
}
}
这个实现也是为了延迟实例化,并且确保线程安全,毕竟double check的实现比较麻烦。
五、
package practise;
public enum Singleton5
{
INSTANCE;
}
这种方法在功能上与公有域方法接近,但是它更加简洁,无偿提供了序列化机制,绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候。单元素的枚举方法已经成为实现Singleton的最佳方法。——《Effective JAVA》