经典Java面试题——单例模式

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_42237752/article/details/102488224

单例模式要点

  1. 一是某个类智能有一个实例;(构造器私有化)
  2. 二是它必须自行创建这个实例;(含有一个该类的静态变量来保存这个唯一的实例)
  3. 三是它必须自行向整个系统提供这个实例;(对外提供获取该实例的方式:1、直接暴露 2、用静态变量的get方法获取)

几种常见形式

  1. 饿汉式:直接创建对象,不存在线程安全问题
    直接实例化饿汉式(简单直观)
    枚举式(最简洁)
    静态代码块饿汉式(适合复杂实例化)
/*
 * 饿汉式:
 * 	直接创建实例对象,不管你是否需要这个对象
 * 
 * (1)构造器私有化
 * (2)自行创建,并使用静态变量保存
 * (3)向外提供这个实例
 * (4)强调这个是单例,我们可以使用final修改
 */

public class Singleton1 {
	public static final Singleton1 INSTANCE = new Singleton1();
	private Singleton1(){
		
	}
}


/*
 * 饿汉式:
 * 	枚举类型,表示该类型的对象是优先的几个
 * 	我们限定为一个,就成了单例
 * 
 */
public enum Singleton2 {
	INSTANCE	
}
/*
 * 饿汉式:
 * 	静态代码快 一般用于比较复杂的初始化
 *  例如:需要从配置文件中加载信息进行初始化。
 * 
 */
public class Singleton3 {

	public static final Singleton3 INSTANCE;
	private String info;
	
	
	static{
		try {
			Properties properties = new Properties();
			properties.load(Singleton3.class.getClassLoader().getResourceAsStream("single.properties"));
			
			INSTANCE = new Singleton3(properties.getProperty("info"));
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	private Singleton3(String info){
		this.info = info;
	}
	public String getInfo() {
		return info;
	}
	public void setInfo(String info) {
		this.info = info;
	}
	@Override
	public String toString() {
		return "Singleton3 [info=" + info + "]";
	}
	
	
	
}
//测试代码
public class test {

	public static void main(String[] args) {
		Singleton1 singleton1 = Singleton1.INSTANCE;
		System.out.println(singleton1);
		Singleton2 s = Singleton2.INSTANCE;
		System.out.println(s);
		
		Singleton3 singleton3 = Singleton3.INSTANCE;
		System.out.println(singleton3);
	}

}
  1. 懒汉式:
    线程不安全(适用于单线程)
    线程安全(适用于多线程)
    静态内部类形式(适用于多线程)
/*
 * 懒汉式:
 * 	延迟创建这个实例对象
 *  会产生线程安全问题
 * 
 * (1)构造器私有化
 * (2)用一个静态变量保存这个唯一的实例
 * (3)提供一个静态方法,获取这个实例对象
 */
public class Singleton4 {
	private static Singleton4 instance;
	private Singleton4(){
		
	}
	public static Singleton4 getInstance(){
		if (instance ==null) {
		    //线程安全问题主要是在这出现。
			instance = new Singleton4();
		}
		return instance;
	}
	
}

/*
 * 懒汉式:
 * 	延迟创建这个实例对象
 *  通过加上锁后成为线程安全的
 */
public class Singleton5 {
	private static volatile Singleton5 instance;//加volatile是防止在多线程中出现指令重排
	private Singleton5(){
		
	}
	public static Singleton5 getInstance(){
		if (instance == null) { //这句是为了提高效率,不用所有线程都等待这个锁
			synchronized (Singleton5.class) {
				if (instance ==null) {
					instance = new Singleton5();
				}
				return instance;
			}
		}
		return instance;
	}
	
}

/*
 * 在内部类被加载和初始化时,才创建INSTANCE实例对象
 * 静态内部类不会自动随着外部类的加载和初始化而初始化,他是要单独去加载和初始化的。
 * 因为是内部类加载和初始化时创建的,因此是线程安全的。(类加载过程是线程安全的)
 */

public class Singleton6 {
	
	private Singleton6(){
		
	}
	private static class Inner{
		private static final Singleton6 INSTANCE = new Singleton6();
		
	}
	
	public static Singleton6 getInstance() {
		return Inner.INSTANCE;
	}
}

总结:
饿汉式中是枚举类型最简单
懒汉式中是静态内部类形式最简单

猜你喜欢

转载自blog.csdn.net/weixin_42237752/article/details/102488224