1)通过静态常量实现的饿汉单例模式,类一加载即初始化,没有并发问题,但是如果类初始化过大,甚至后期没有使用,会造成资源浪费。
public class HungrySingleton {
private final static HungrySingleton INSTANCE = new HungrySingleton();
/*私有构造方法,防止被实例化*/
private HungrySingleton() {}
public HungrySingleton getInstance(){
return INSTANCE;
}
public Object readResolve(){
return INSTANCE;
}
}
2)通过静态代码块实现的饿汉式单例,跟第一种一样的问题,类一加载即初始化,没有并发问题,但是如果类初始化过大,甚至后期没有使用,会造成资源浪费。
public class HungrySingleton {
private static HungrySingleton instance;
static{
instance = new HungrySingleton();
}
/*私有构造方法,防止被实例化*/
private HungrySingleton() {}
public HungrySingleton getInstance(){
return INSTANCE;
}
public Object readResolve(){
return INSTANCE;
}
}
3)一般的懒汉式单例模式,毫无线程安全保护,如果我们把他放入多线程的环境下,肯定会出现线程安全问题。
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
public Object readResolve() {
return instance;
}
}
4)通过synchronzied修饰方法的懒汉式单例模式,synchronzied关键字会把对象锁住,每次调用getInstance()时,都要把对象锁住,性能会有所下降。
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {
}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
public Object readResolve() {
return instance;
}
}
5)通过synchronzied修饰代码块的懒汉式单例模式,这种方式,本意是想对第四种实现方式的改进,因为前面同步方法效率太低,改为同步产生实例化的的代码块,但是这种同步并不能起到线程同步的作用。跟第3种实现方式遇到的情形一致,假如一个线程进入了if (instance== null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {
}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
instance = new LazySingleton();
}
}
return instance;
}
public Object readResolve() {
return instance;
}
}
6)双重检查的单例模式,Double-Check概念是多线程开发中常使用到的,如代码中所示,我们进行了两次if (instance == null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象,也避免的反复进行方法同步,这种做法既可以保证线程安全,又可以延迟加载,效率较高。
public class LazyDoubleCheckSingleton {
public static LazyDoubleCheckSingleton instance = null;
public LazyDoubleCheckSingleton() {
}
public static LazyDoubleCheckSingleton getInstance() {
if (instance == null) {
synchronized (instance) {
if (instance == null) {
instance = new LazyDoubleCheckSingleton();
}
}
}
return instance;
}
public Object readResolve() {
return instance;
}
}
7)通过静态内部类实现的单例模式,当LazyInnerSingleton第一次被加载的时,并不会去加载SingletonInstance,只有当getInstance()方法第一次调用的时候,才会去初始化INSTANCE,第一次调用调用getInstance()方法会使虚拟机去加载SingletonInstance类,这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。
public class LazyInnerSingleton {
public static LazyInnerSingleton instance = null;
public LazyInnerSingleton() {
}
// 定义一个内部类,用来获得实例
private static class SingletonInstance {
private static final LazyInnerSingleton INSTANCE = new LazyInnerSingleton();
}
public static LazyInnerSingleton getInstance(){
return SingletonInstance.INSTANCE;
}
public Object readResolve() {
return instance;
}
}
8)通过枚举实现的单例模式,这借助JDK1.5中添加的枚举来实现单例模式,枚举类型是线程安全的,并且只会装载一次,不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
package singleton.enums;
public class Singleton {
private String name;
private String desc;
}
package singleton.enums;
public enum SingletonEnum {
INSTANCE;
private Singleton instance = null;
private SingletonEnum(){
instance = new Singleton();
}
public Singleton getInstance(){
return instance;
}
}
网友评论