Java设计模式--单例模式

发布于:2025-03-29 ⋅ 阅读:(23) ⋅ 点赞:(0)
单例模式(构造器私有)

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,有以下特点:

  • 单例类只能有一个实例。

  • 单例类必须自己创建自己的唯一实例。

  • 单例类必须给所有其他对象提供这一实例。

反射可以破坏单例模式!!!

饿汉式

这种方式比较常用,但容易产生垃圾对象 优点:没有加锁,执行效率会提高。 缺点:类加载时就初始化,浪费内存。

 
package com.lyc.single;
 //饿汉式单例
 public class Hungry {
     //可能会浪费空间
     private byte[] bytes1= new byte[1024*1024];
     private byte[] bytes2= new byte[1024*1024];
     private byte[] bytes3= new byte[1024*1024];
     private byte[] bytes4= new byte[1024*1024];
     private Hungry(){
 ​
     }
     private static final Hungry instance = new Hungry();//创建对象
     public static Hungry getInstance(){
         return instance;
     }
 }
 ​
懒汉式

DCL懒汉式:在懒汉式基础上加入双重检验锁,保证线程安全和性能。

 
package com.lyc.single;
 //懒汉式单例模式
 public class LazyMan {
     private LazyMan(){
 ​
     }
     private volatile static LazyMan lazyMan;
     public LazyMan getInstance(){
         //双重检测锁模式的懒汉式单例,简称:DCL懒汉式
         if (lazyMan==null){
            synchronized (LazyMan.class){
                if (lazyMan==null){
                    lazyMan=new LazyMan();//不是一个原子性操作
                    //1.分配内存给这个对象
                    //2.执行构造方法,初始化对象
                    //3.将这个对象指向这个空间
                    //可能会发生指令重排,导致对象还没初始化完成,就返回了
                    //如果有两个线程在创建对象,可能会造成对象还没初始化完成,就返回了
                    //如果在创建对象时,多个线程同时判断到lazyMan==null,就会创建多个对象
                    //解决方法:
                    //1.使用synchronized关键字
                    //2.使用volatile关键字
                }
            }
         }
         return lazyMan;
     }
     //单线程下是安全的
     //多线程下是不安全的,需要在加锁。
 }
 ​

静态内部类

 package com.lyc.single;
 //静态内部类实现
 public class Holder {
     private Holder(){
 ​
     }
     public static Holder getInstance(){
         return  InnerClass.holder;
     }
     public static class InnerClass{
         private static final Holder holder = new Holder();
     }
 }

单例不安全,因为有反射

枚举

 package com.lyc.single;
 ​
 import java.lang.reflect.Method;
 ​
 //enum是什么,枚举本身也是一个Class类
 public enum EnumSingle {
     INSTANCE;
 ​
     public EnumSingle getInstance() {
         return INSTANCE;
     }
 }
 ​
 package com.lyc.single;
 ​
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 ​
 public class SingleTest {
     public static void main(String[] args) throws Exception{
         EnumSingle instance = EnumSingle.INSTANCE;
         Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class, int.class);
         declaredConstructor.setAccessible(true);
         EnumSingle instance1 = declaredConstructor.newInstance();
         System.out.println(instance.hashCode());
         System.out.println(instance1.hashCode());
     }
 }
 ​