单例模式
1、概念:提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
2、作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
3、常见的五种单例模式实现方式:
- 饿汉式(线程安全,调用率高,不能延迟加载)
- 懒汉式(线程安全,调用效率不高,可以延迟加载)
- DCL懒汉式(由于JVM底层内部模型原因,偶尔会出现问题,不建议使用)
- 懒汉式改进:静态内部类式(线程安全,调用率高,可以延时加载)
- 枚举单例(线程安全,调用率高,不能延时加载)
一、饿汉式
//饿汉式单例
public class SingletonDemo01 {
//1、私有化构造器
private SingletonDemo01() {
}
//2、类初始化的时候就立即加载该对象
private static SingletonDemo01 instance = new SingletonDemo01();
//3、提供获取该对象的方法,没有synchronized,效率高
public static SingletonDemo01 getInstance() {
return instance;
}
}
class SingletonDemo01Test{
public static void main(String[] args) {
SingletonDemo01 instance = SingletonDemo01.getInstance();
SingletonDemo01 instance2 = SingletonDemo01.getInstance();
System.out.println(instance == instance2); // true
}
}
二、懒汉式
1、单线程下的懒汉式:
//懒汉式
public class SingletonDemo02 {
//1、私有化构造器
private SingletonDemo02() {}
//2、类初始化的时候就不立即加载该对象
private static SingletonDemo02 instance;
// //3、提供获取该对象的方法
public static SingletonDemo02 getInstance() {
if (instance == null) {
instance = new SingletonDemo02();
}
return instance;
}
}
2、多线程下的懒汉式:
public class SingletonDemo02 {
//1、私有化构造器
private SingletonDemo02() {
}
//2、类初始化的时候就不立即加载该对象
private static SingletonDemo02 instance;
// //3、提供获取该对象的方法,有synchronized,效率较低
public static synchronized SingletonDemo02 getInstance() {
if (instance == null) {
instance = new SingletonDemo02();
}
return instance;
}
}
class SingletonDemo02Test{
public static void main(String[] args) {
SingletonDemo02 instance = SingletonDemo02.getInstance();
SingletonDemo02 instance2 = SingletonDemo02.getInstance();
System.out.println(instance == instance2); // true
}
}
三、DCL懒汉式(双重校验锁)
//DCL懒汉式
public class SingletonDemo03 {
//1、私有化构造器
private SingletonDemo03() {
}
//2、类初始化的时候就不立即加载该对象
private volatile static SingletonDemo03 instance;
// //3、提供获取该对象的方法,有synchronized,效率较低
public static SingletonDemo03 getInstance() {
if (instance == null) {
synchronized (SingletonDemo03.class) {
if(instance == null) {
instance = new SingletonDemo03();
}
}
}
return instance;
}
}
class SingletonDemo03Test{
public static void main(String[] args) {
SingletonDemo03 instance = SingletonDemo03.getInstance();
SingletonDemo03 instance2 = SingletonDemo03.getInstance();
System.out.println(instance == instance2); // true
}
}
四、静态内部类
//静态内部类
public class SingletonDemo04 {
private static class InnerClass{
private static final SingletonDemo04 instance = new SingletonDemo04();
}
public static SingletonDemo04 getInstance() {
return InnerClass.instance;
}
}
//反射机制:可以破坏我们以上的单例;
class SingletonDemo04Test{
public static void main(String[] args) throws Exception {
Constructor<SingletonDemo04> declaredConstructor = SingletonDemo04.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
SingletonDemo04 instance = declaredConstructor.newInstance();
SingletonDemo04 instance2 = declaredConstructor.newInstance();
System.out.println(instance == instance2);
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
}
}
改进:
import java.lang.reflect.Constructor;
//静态内部类
public class SingletonDemo04 {
public static boolean flag = false;
//1、私有化构造器
private SingletonDemo04() {
synchronized (SingletonDemo03.class) {
if(flag == false) {
flag = true;
}else {
throw new RuntimeException("不要试图用反射来破坏我们的单例");
}
}
}
private static class InnerClass{
private static final SingletonDemo04 instance = new SingletonDemo04();
}
public static SingletonDemo04 getInstance() {
return InnerClass.instance;
}
}
//反射机制:可以破坏我们以上的单例;
class SingletonDemo04Test{
public static void main(String[] args) throws Exception {
SingletonDemo04 instance = SingletonDemo04.getInstance();
Constructor<SingletonDemo04> declaredConstructor = SingletonDemo04.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
SingletonDemo04 instance2 = declaredConstructor.newInstance();
System.out.println(instance == instance2);
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
}
}
五、枚举方式
最好的方式:
public enum SingletonDemo05 {
INSTANCE;
public SingletonDemo05 getInstance() {
return INSTANCE;
}
}
class SingletonDemo05Test{
public static void main(String[] args) {
SingletonDemo05 instance = SingletonDemo05.INSTANCE;
SingletonDemo05 instance2 = SingletonDemo05.INSTANCE;
System.out.println(instance == instance2);//true
}
}
总结:上面五种方式最好的为枚举形式,在面试中多线程环境下写DCL懒汉式。