简介
单例模式是一种常见的设计模式,其定义是单例对象的类,在虚拟机中只运行一个实例存在。在多线程环境下,应该提供一定的机制,确保只会产生一个实例
一、饿汉式--静态变量(推荐)
public class MySingleton1 {
private static MySingleton1 instance = new MySingleton1();
public static MySingleton1 getInstance() {
return instance;
}
private MySingleton1() {
}
}
此方法利用了JVM的类加载机制,确保了单例对象只会被实例化一次,保证了线程安全。同时,在MySingleton1类被加载时,就完成了实例化,没有达到懒加载的效果。假设始终没有用法该示例,则会造成浪费内存资源。
二、饿汉式--静态代码块(推荐)
public class MySingleton2 {
private static MySingleton2 instance;
static {
instance = new MySingleton2();
}
private MySingleton2() {
}
public static MySingleton2 getInstance() {
return instance;
}
}
与上一种方式相似,前者利用静态变量,后者利用静态代码块,都是利用JVM的类加载机制,保证只会被实例化一次。
三、懒汉式(不推荐)
public class MySingleton3 {
private static MySingleton3 instance;
private MySingleton3() {
}
public static MySingleton3 getInstance() {
if (instance == null) {
instance = new MySingleton3();
}
return instance;
}
}
在多线程环境下,此方式存在线程安全问题。假设两个线程同时判断instance == null的结果为true,则它们会各自去实例化对象,然后就会产生两个实例,这违背了单例模式的原则。
四、懒汉式--同步方法
public class MySingleton4 {
private static MySingleton4 instance;
private MySingleton4() {
}
public static synchronized MySingleton4 getInstance() {
if (instance == null) {
instance = new MySingleton4();
}
return instance;
}
}
相对于上一种方式,这里给getInstance()方法加上的同步关键字,解决了线程安全,但是也降低了效率,一般不推荐
五、双重检查(推荐)
public class MySingleton5 {
private static volatile MySingleton5 instance;
private MySingleton5() {
}
public static MySingleton5 getInstance() {
if (instance == null) {
synchronized (MySingleton5.class) {
if (instance == null) {
instance = new MySingleton5();
}
}
}
return instance;
}
}
与上一种方式相比,同步锁的粒度变小了,大大提高了效率,而且双重检查机制,保证了只会实例化一次
六、内部静态类(推荐)
public class MySingleton6 {
private MySingleton6() {
}
private static class MySingleton6Instance {
private static final MySingleton6 instance = new MySingleton6();
}
public static MySingleton6 getInstance() {
return MySingleton6Instance.instance;
}
}
这种实现方式和饿汉式相似,都是利用jvm类加载机制来保证只被实例化一次。与饿汉式不同的是,饿汉式在类加载时完成了实例化,而此种方式下,只会在第一次用到getInstance()方法,才会被实例化。
七、枚举(推荐)
public enum MySingleton7 {
RED, BLACK;
}
枚举很简单,上面的RED、BLACK都是单例的,jvm中只会存在一个实例。
单例测试:
public class MySingletonMain {
public static void main(String[] args) {
System.out.println(MySingleton1.getInstance() == MySingleton1.getInstance());
System.out.println(MySingleton2.getInstance() == MySingleton2.getInstance());
System.out.println(MySingleton3.getInstance() == MySingleton3.getInstance());
System.out.println(MySingleton4.getInstance() == MySingleton4.getInstance());
System.out.println(MySingleton5.getInstance() == MySingleton5.getInstance());
System.out.println(MySingleton6.getInstance() == MySingleton6.getInstance());
System.out.println(MySingleton7.RED == MySingleton7.RED);
}
}
单线程环境下,上述所有输出都是true。如果是多线程环境的话,上述提到的线程不安全的实现方式,输出的结果可能会出现false,读者可以自己去实验。就我个人而言,我在实际开发中,一般会采用静态内部类和枚举这两种方式~~~