java设计模式 创建型-单例模式

单例模式基本概念

所谓类的单例设计模式:就是采用一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个只提供一个取得其对象实例的方法。

  • 整个应用中只存在一个实例。
  • 该类只提供一个方法获取该实例。

java实现单例模式的7种方式

  • 1、饿汉式-静态变量
  • 2、饿汉式-静态代码块
  • 3、懒汉式-单线程方式
  • 4、懒汉式-同步方法
  • 5、懒汉式-同步代码块,双重检查
  • 6、懒汉式-静态内部类
  • 7、懒汉式-枚举

1、 饿汉式-静态变量

  • 构造器私有化,使得外部不能new,也不能继承。
  • 在本类内部创建对象实例。
  • 提供一个公有的静态方法,用于返回实例对象。
public class Singleton {

	private Singleton(){
	}

	private final static Singleton instance = new Singleton();

	public static Singleton getInstance(){
		return instance;
	}
}

饿汉式-静态变量优缺点

  • 写法简单,单例在类加载的时候完成实例化;利用类加载机制,避免了线程同步问题。
  • 但是在类加载的时候就完成了实例化,没有达到懒加载的效果。如果从始至终都没有使用过这个单例,就会造成内存浪费。
  • 这种基于classloader机制避免了线程同步问题,不过,instance在类加载时就实例化了,在单例模式中大多数都是调用了getInstance方法。但是导致类加载的原因有很多,不能确定其他方法(或静态方法)导致了类的加载,这时候初始化instance就meiyou达到懒加载的效果。

结论:

  • 这种单例模式推荐使用,不过最好是能确保该单例在应用中一定能被使用到。否则会造成内存浪费。


2、饿汉式-静态代码块

public class Singleton {
	
	private static Singleton instance;
	static {
		instance = new Singleton();
	}
	private Singleton(){  }
	public static Singleton getInstance(){
		return instance;
	}
}

静态变量初始化 与 静态代码块 的初始化时机类似。都是利用了classloader机制来避免线程同步问题。



3、懒汉式-单线程方式

public class Singleton {
	//创建静态变量
	private static Singleton instance;
	//私有化构造方法	
	private Singleton(){  }
	//在获取实例的公有方法中去判断是否存在对象,如果存在就返回,不存在就创建。
	public static Singleton getInstance(){
		if( instance == null ){
				instance == new Singleton();
		}
		return instance;
	}
}

懒汉式-单线程方式的优缺点

  • 这种方式起到了懒加载创建单实例的效果,但是只能在单线程语言下使用。比如js。
  • 如果在多线程下,可能有多个线程进入到if( instance == null ){ … }的代码块内,从而会创建多个实例。所以在多线程环境下不可使用这种方式。

结论

  • 对于多线程语言: 这种懒汉式不推荐使用,有创建多个实例的潜在风险。


4、懒汉式-同步方法

public class Singleton {

	private static Singleton instance;
	private Singleton(){}

	//提供一个静态的公有方法,加入同步处理的代码synchronized,解决线程安全问题。
	public static synchronized Singleton getInstance(){
		if( instance == null ){
			instance = new Singleton();
		}
		return instance;
	}
}

懒汉式-同步方法 优缺点:

  • 使用同步方法解决了线程不安全问题。且也是懒加载方式。
  • 但是效率太低,每个线程在想获取类的实例的时候,执行getInstance()方法都要进行同步。但实际上同步只需要在第一次执行这个方法的时候就够了,以后获取该实例的时候,直接return就行。

结论:

  • 实际开发过程中,不推荐使用这种方式。


5、懒汉式-同步代码块

public class Singleton {
	private static volatile Singleton instance;
	public Singleton(){}

	public static Singleton getInstance(){
		if( instance == null ){
			synchronized ( Singleton.class ){
				if( instance == null ){
					instance = new Singleton();
				}
			}
		}
	}
	return instance;
}

懒汉式-同步代码块 优缺点

  • Double-check概念在多线程开发过程中常使用到。如代码中所示,我们进行两次if(instance === null)检查,这样就能保证线程安全。
  • Double-check的方式,实例化代码只执行一次,后面再次访问时,判断if(instance == null){ … }直接return实例化对象,也避免了反复进行方法同步的判断。
  • volatile是轻量级的synchronized,能够保证Singleton对象创建之后,立刻被其他线程知道。volatile关键字只能修饰变量。

结论

  • 懒加载,线程安全,效率高。
  • 在实际使用过程中,推荐使用这种方式。


6、懒汉式-静态内部类

静态内部类的特点:

  • 外部类被装在时,静态内部类不会被装载。
  • 只有外部类的方法调用时,方法内部如果调用静态内部类的方法或者成员变量,该静态内部类才会被装载,而且只会被装载一次。且能利用classloader机制来保证线程安全。
public class Singleton {
	private Singleton(){}
	private static class SingletonInstance {
		//内部类能获取外部类的私有方法,并且使用。
		private static final INSTANCE = new Singleton();
	}
	//当第一次调用这个方法时,触发了静态内部类的加载,同时在静态内部类中创建了Singleton实例。以后的调用就不会再触发类加载,而是直接返回Singleton实例。
	private static Singleton getInstance(){
		return SingletonInstance.INSTANCE;
	}
}

说明

  • 通过静态内部类方式创建单例,是利用了classloader机制来保证初始化实例时避免了线程同步问题。
  • 静态内部类方式在Singleton类被加载时并不会立刻实例化,而是在需要实例化时,调用getInstance方法,才会进行Singleton的实例化。
  • 类的静态属性只会在第一次加载类的时候进行初始化,所以在这里,jvm帮助我们保证了线程的安全,在类进行初始化时,别的线程是无法进入的。

优点

  • 懒加载,线程安全,效率高。
  • 推荐使用。


七、 单例-枚举形式

  • 枚举的属性就是一个实例。
  • 借助JDK1.5中添加的枚举来实现单例模式,不仅能避免多线程同步问题,而且还能防止反序列化重新新的对象。
public enum Singleton {
	INSTANCE;
	public void method(){
		...
	}
}

结论

  • 最推荐使用的方式。


单例模式在JDK中的使用

  • jdk中Runtime就是使用饿汉式创建的单例。利用classloader的机制保证线程安全。
public class Runtime {

	private static Runtime currentRuntime = new Runtime();
	private Runtime(){}
	public static Runtime getRuntime(){
		return currentRuntime;
	}
}
发布了58 篇原创文章 · 获赞 34 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_36723759/article/details/104105961
今日推荐