单例模式的7种实现方式及分析

第一种

  • 代码
package com.xiayc.singleton;

/**
 * 饿汉模式
 * @author xyc
 *
 */
public class Hungry {
	private Hungry() {
		
	}
	
	private volatile static Hungry singleton = new Hungry();
	
	public static Hungry getSingleton() {
		return singleton;
	}
	
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println(Hungry.getSingleton());
				}
			}).start();
		}
	}
}

  • 执行结果
com.xiayc.singleton.Hungry@1ea452f5
com.xiayc.singleton.Hungry@1ea452f5
com.xiayc.singleton.Hungry@1ea452f5
com.xiayc.singleton.Hungry@1ea452f5
com.xiayc.singleton.Hungry@1ea452f5
com.xiayc.singleton.Hungry@1ea452f5
com.xiayc.singleton.Hungry@1ea452f5
com.xiayc.singleton.Hungry@1ea452f5
com.xiayc.singleton.Hungry@1ea452f5
com.xiayc.singleton.Hungry@1ea452f5	
  • 分析

  实例变量的hashCode值一致,说明对象是同一个,饿汉式单例实现是线程安全的,
  缺点是该类加载的时候就会直接new 一个静态对象出来,当系统中这样的类较多时,会使得启动速度变慢 ,且不符合懒加载思想。

第二种

  • 代码
package com.xiayc.singleton;

/**
 * 懒汉模式
 * @author xyc
 *
 */
public class Lazy {
	private Lazy() {
		
	}
	
	private volatile static Lazy singleton = null;
	
	public static Lazy getSingleton() {
		if(singleton==null) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			singleton = new Lazy();
		}
		return singleton;
	}
	
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println(Lazy.getSingleton());
				}
			}).start();
		}
	}
}

  • 执行结果
com.xiayc.singleton.Lazy@1ea452f5
com.xiayc.singleton.Lazy@7ec5aaaa
com.xiayc.singleton.Lazy@c16150
com.xiayc.singleton.Lazy@1d49826
com.xiayc.singleton.Lazy@423430c8
com.xiayc.singleton.Lazy@58bb45bd
com.xiayc.singleton.Lazy@277ea783
com.xiayc.singleton.Lazy@40d9c054
com.xiayc.singleton.Lazy@27958c7
com.xiayc.singleton.Lazy@50d03d7f
  • 分析

  实例变量的hashCode值不一致,说明对象不是同一个,懒汉式单例实现是非线程安全的。
  优点是实现了懒加载思想。

第三种

  • 代码
package com.xiayc.singleton;

public class SyncMethodLazy {
	private SyncMethodLazy() {
		
	}
	
	private static SyncMethodLazy singleton = null;
	
	public static synchronized SyncMethodLazy getSingleton() {
		if(singleton==null) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			singleton = new SyncMethodLazy();
		}
		return singleton;
	}
	
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println(SyncMethodLazy.getSingleton());
				}
			}).start();
		}
	}
}

  • 执行结果
com.xiayc.singleton.SyncMethodLazy@40d9c054
com.xiayc.singleton.SyncMethodLazy@40d9c054
com.xiayc.singleton.SyncMethodLazy@40d9c054
com.xiayc.singleton.SyncMethodLazy@40d9c054
com.xiayc.singleton.SyncMethodLazy@40d9c054
com.xiayc.singleton.SyncMethodLazy@40d9c054
com.xiayc.singleton.SyncMethodLazy@40d9c054
com.xiayc.singleton.SyncMethodLazy@40d9c054
com.xiayc.singleton.SyncMethodLazy@40d9c054
com.xiayc.singleton.SyncMethodLazy@40d9c054
  • 分析

  实例变量的hashCode值一致,说明对象是同一个,使用synchronized关键字的懒汉式单例实现是线程安全的。
  优点是实现了线程安全并且是懒加载的;缺点是在同一时刻getSingleton方法只能由一个线程访问,效率会很低。

第四种

  • 代码
package com.xiayc.singleton;

public class SyncFullCodeBlockLazy {
	private SyncFullCodeBlockLazy() {
		
	}
	
	private static SyncFullCodeBlockLazy singleton = null;
	
	public static SyncFullCodeBlockLazy getSingleton() {
		synchronized (SyncFullCodeBlockLazy.class) {
			if(singleton==null) {
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				singleton = new SyncFullCodeBlockLazy();
			}
			return singleton;
		}
	}
	
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println(SyncFullCodeBlockLazy.getSingleton());
				}
			}).start();
		}
	}
}
  • 执行结果
com.xiayc.singleton.SyncFullCodeBlockLazy@1ea452f5			com.xiayc.singleton.SyncFullCodeBlockLazy@1ea452f5		com.xiayc.singleton.SyncFullCodeBlockLazy@1ea452f5		com.xiayc.singleton.SyncFullCodeBlockLazy@1ea452f5			com.xiayc.singleton.SyncFullCodeBlockLazy@1ea452f5			com.xiayc.singleton.SyncFullCodeBlockLazy@1ea452f5			com.xiayc.singleton.SyncFullCodeBlockLazy@1ea452f5			com.xiayc.singleton.SyncFullCodeBlockLazy@1ea452f5			com.xiayc.singleton.SyncFullCodeBlockLazy@1ea452f5			com.xiayc.singleton.SyncFullCodeBlockLazy@1ea452f5
  • 分析

  实例变量的hashCode值一致,说明对象是同一个,使用synchronized关键字修饰全部代码块的懒汉式单例实现是线程安全的。
  这种实现方式其实和synchronized修饰方法的实现方式优缺点一致。

第五种

  • 代码
package com.xiayc.singleton;

public class SyncPartCodeBlockLazy {
	private SyncPartCodeBlockLazy() {
		
	}
	
	private static SyncPartCodeBlockLazy singleton = null;
	
	public static SyncPartCodeBlockLazy getSingleton() {
		if(singleton==null) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (SyncPartCodeBlockLazy.class) {
				singleton = new SyncPartCodeBlockLazy();
			}
		}
		return singleton;
	}
	
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println(SyncPartCodeBlockLazy.getSingleton());
				}
			}).start();
		}
		
	}
}
  • 执行结果
com.xiayc.singleton.SyncPartCodeBlockLazy@7ec5aaaa
com.xiayc.singleton.SyncPartCodeBlockLazy@1d49826	com.xiayc.singleton.SyncPartCodeBlockLazy@277ea783	com.xiayc.singleton.SyncPartCodeBlockLazy@50d03d7f	com.xiayc.singleton.SyncPartCodeBlockLazy@58bb45bd	com.xiayc.singleton.SyncPartCodeBlockLazy@1ea452f5	com.xiayc.singleton.SyncPartCodeBlockLazy@27958c7		com.xiayc.singleton.SyncPartCodeBlockLazy@423430c8		com.xiayc.singleton.SyncPartCodeBlockLazy@40d9c054		com.xiayc.singleton.SyncPartCodeBlockLazy@c16150
  • 分析

  实例变量的hashCode值不一致,说明对象不是同一个,使用synchronized关键字修饰局部代码块的懒汉式单例实现是非线程安全的。
  虽然这种实现方法相较于第三种和第四种方式效率要高一些,但并非线程安全的。

第六种

  • 代码
package com.xiayc.singleton;

public class SyncDoubleCheckLazy {
	private SyncDoubleCheckLazy() {
		
	}
	
	private static SyncDoubleCheckLazy singleton = null;
	
	public static SyncDoubleCheckLazy getSingleton() {
		if(singleton==null) {
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (SyncDoubleCheckLazy.class) {
				if(singleton==null) {
					singleton = new SyncDoubleCheckLazy();
				}
			}
		}
		return singleton;
	}
	
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println(SyncDoubleCheckLazy.getSingleton());
				}
			}).start();
		}
	}
}

  • 执行结果
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
  • 分析

  实例变量的hashCode值一致,说明对象是同一个,使用synchronized关键字双重检查的懒汉式单例实现是线程安全的。
  其实这种方式是综合了第三、四、五这三种实现方式,即实现了线程安全,也相对提高了运行效率,值得推荐。

第七种

  • 代码
package com.xiayc.singleton;

public class StaticInnerClass {
	private StaticInnerClass() {
		
	}
	
    private static class StaticInnerClassProvider{  
        private static StaticInnerClass singleton = new StaticInnerClass();  
    }
    
    public static StaticInnerClass getSingleton() {
		return StaticInnerClassProvider.singleton;
	}
	
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println(StaticInnerClass.getSingleton());
				}
			}).start();
		}
	}
}

  • 执行结果
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
com.xiayc.singleton.SyncDoubleCheckLazy@423430c8
  • 分析

  实例变量的hashCode值一致,说明对象是同一个,使用静态内部类方式的懒汉式单例实现是线程安全的。
  虽然咋看上去这种方式和第一种饿汉模式的单例模式一样,两者都是采用了类装载的机制来保证初始化实例时只有一个线程,但是有区别的地方在于静态内部类方式在StaticInnerClass类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载StaticInnerClassProvider类,从而完成StaticInnerClass的实例化,所以这种方式也值得推荐。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值