《剑指Offer》面试题2(设计模式之单例模式):实现Singleton模式(Java实现)

题目:设计一个类,只能生成该类的一个实例。

分析:只能生成一个实例的类是实现了Singleton(单例)模式的类型,保证一个系统中的某个类只有一个实例而且该实例易于外界访问。

大体步骤:

单例模式设计步骤
1、 构造方法私有化(private)
2、 定义一个私有的(private)静态(static)实例化对象
3、 对外提供一个公共的(public)静态(static)方法返回该实例

        以下综合了收集到的各种方法进行了测试

package com.xlx.Offer;

/**
 * @author 谢凌宣
 *  
 * 《剑指Offer》面试题2:实现Singleton模式
 * 要求:设计一个类,只能生成该类的一个实例,即实现单例模式
 * 
 * 大体步骤:
 *     1、构造方法私有化(private)
 *     2、定义一个私有的(private)静态(static)实例化对象
 *     3、对外提供一个公共的(public)静态(static)方法返回该实例
 */
public class Test02 {

	/**
	 * 单例模式,饿汉式,线程安全
	 * 
	 * 步骤:
	 *     1、定义一个私有的构造方法;
	 *     2、定义一个私有的实例化对象,并加上static和final修饰符;
	 *     3、然后通过公共的静态方法调用返回实例。
	 * 
	 * 优点:简单,并且不会因为没有加synchronized关键字而造成线程不安全问题。
	 * 缺点:当该类被加载时,会初始化该实例和静态变量并被创建分配内存空间,会一直占用内存。
	 */
	public static class Singleton1 {
		private Singleton1() {
			//构造函数设为私有,以禁止他人创建实例,确保只创建一个实例
		}
		
		private final static Singleton1 INSTANCE = new Singleton1();
		
		public static Singleton1 getInstance() {
			return INSTANCE;
		}
	}
	
	/**
	 * 单例模式,饱(懒)汉式,只用于单线程,多线程不安全
	 * 
	 * 步骤:
	 *     1、定义一个私有的构造方法;
	 *     2、定义一个该类的静态私有变量;
	 *     3、然后定义一个公共的静态方法,接着对变量的值进行空值判定,为空则构建实例化对象,不为空则直接返回即可。
	 * 
	 * 优点:简单,当第一次调用时才会被初始化,节省内存空间。
	 * 缺点:线程不安全,多个线程调用会出现多个实例。
	 */
	public static class Singleton2 {
		private Singleton2() {
			//构造函数设为私有,以禁止他人创建实例,确保只创建一个实例
		}
		
		private static Singleton2 instance = null;
		
		public static Singleton2 getInstance() {
			if(instance == null) {
				instance = new Singleton2();
			}
			return instance;
		}
	}
	
	/**
	 * 单例模式,饱(懒)汉式,线程安全
	 * 
	 * 加synchronized关键字,保证线程安全
	 */
	public static class Singleton3 {
		private Singleton3() {
			//构造函数设为私有,以禁止他人创建实例,确保只创建一个实例
		}
		
		private static Singleton3 instance = null;
		
		public static synchronized Singleton3 getInstance() {
			if(instance == null) {
				instance = new Singleton3();
			}
			return instance;
		}
	}
	
	/**
	 * 单例模式,懒汉式变种,线程安全
	 */
	public static class Singleton4 {
		private Singleton4() {}
		
		public static Singleton4 instance = null;
		static {
			instance = new Singleton4();
		}
		
		public static Singleton4 getInstance() {
			return instance;
		}
	}
	
	/**
	 * 单例模式,使用静态内部类,线程安全(推荐)
	 * 
	 * 步骤:
	 *     1、定义一个私有的构造方法;
	 *     2、定义一个该类私有的静态内部类,然后在内部类中定义该类的私有的静态内部变量;
	 *     3、通过公共的final修饰的静态方法调用并返回实例。
	 * 
	 * 优点:因为内部类被定义为私有的,除了对外公布的公共静态方法getInstance(),其它是无法访问的。
	 *      又因为它是延迟加载的,所以读取实例的时候不会进行同步,几乎没有性能缺陷,还是线程安全的。
	 */
	public static class Singleton5 {
		private Singleton5() {
			//构造函数设为私有,以禁止他人创建实例,确保只创建一个实例
		}
		
		private final static class SingletonHolder {
			private static final Singleton5 INSTANCE = new Singleton5();
		}
		
		public static final Singleton5 getInstance() {
			return SingletonHolder.INSTANCE;
		}
	}
	
	/**
	 * 使用枚举方式,线程安全(推荐)
	 * 
	 * JDK1.5之后版本可用
	 * 
	 * 优点:完美支持单例模式,并且线程安全,效率高,书写超级简单。
	 */
	public enum Singleton6 {
		INSTANCE;
	}
	
	/**
	 * 使用静态内部类,使用双重校验锁,线程安全(推荐)
	 *  
	 * 步骤:
	 *     1、定义一个私有的构造方法;
	 *     2、通过volatile定义一个静态私有变量,保证变量的可见性;
	 *     3、然后定义一个公共的静态方法,第一次对该对象实例时进行与否判断,不为空直接返回。
	 * 
	 * 优点:内存占用低、效率高、线程安全、多线程操作原子性。
	 */
	public static class Singleton7 {
		private Singleton7() {
			//构造函数设为私有,以禁止他人创建实例,确保只创建一个实例
		}
		
		private volatile static Singleton7 instance = null;
		
		public static Singleton7 getInstance() {
			if(instance == null) {
				synchronized(Singleton7.class) {
					if(instance == null) {
						instance = new Singleton7();
					}
				}
			}
			return instance;
		}
	}
	
	
	
	public static void main(String[] args) {
		System.out.println(Singleton1.getInstance() == Singleton1.getInstance());
		System.out.println(Singleton2.getInstance() == Singleton2.getInstance());
		System.out.println(Singleton3.getInstance() == Singleton3.getInstance());
		System.out.println(Singleton4.getInstance() == Singleton4.getInstance());
		System.out.println(Singleton5.getInstance() == Singleton5.getInstance());
		System.out.println(Singleton6.INSTANCE == Singleton6.INSTANCE);
		System.out.println(Singleton7.getInstance() == Singleton7.getInstance());		
	}

}

猜你喜欢

转载自blog.csdn.net/xielingxuan666/article/details/82112309