单例模式

1、饿汉式

 1 /**
 2  * 饿汉式:类一加载就创建,迫不及待的样子就是饿汉了
 3  * 优点:天生的线程安全
 4  * 缺点:饿汉式类多了就会影响项目启动效率
 5  */
 6 public class SingleInstance01 {
 7     /**
 8      * 私有化构造函数,给出指定方法获取;因是静态属性,类加载时只会创建一次
 9      * 所以线程安全
10      */
11     private static SingleInstance01 singleInstance01 = new SingleInstance01();
12 
13     private SingleInstance01() {
14     }
15 
16     private SingleInstance01 getInstance() {
17         return singleInstance01;
18     }
19 }

2、懒汉式

 1 /**
 2  * 懒汉式:就是要用的时候才创建,不用的时候不创建;懒汉式会出现线程不安全的情况
 3  *
 4  */
 5 public class SingleInstance02 {
 6     private static SingleInstance02 instance02;
 7 
 8     /**
 9      * 记住:单例都要私有化构造函数的;不要问为什么,自己想想哦
10      */
11     private SingleInstance02() {}
12 
13     /**
14      * 给出获取单例的方法
15      */
16     public static SingleInstance02 getInstance(){
17         /**
18          * 为什么不安全?因为多线程的时候该方法同时被调用时,
19          * 该对像会创建多次,成为不同的对像的
20          */
21         if(instance02 == null){
22             instance02=new SingleInstance02();
23         }
24         return instance02;
25     }
26 }

3、懒汉式(线程安全)

 1 /**
 2  * 懒汉式(保证线程安全):就是要用的时候才创建,不用的时候不创建;
 3  *
 4  */
 5 public class SingleInstance03 {
 6     private static SingleInstance03 instance03;
 7 
 8     /**
 9      * 记住:单例都要私有化构造函数的;不要问为什么,自己想想哦
10      */
11     private SingleInstance03() {}
12 
13     /**
14      * 给出获取单例的方法
15      * 同步获取对像的方法,则可保证线程安全了
16      * 缺点:多线程调用时,就会造成执行排队,影响性能
17      */
18     public synchronized static SingleInstance03 getInstance(){
19         if(instance03 == null){
20             instance03=new SingleInstance03();
21         }
22         return instance03;
23     }
24 }

4、双重校验锁

 1 /**
 2  * 双重校验锁:线程安全
 3  * 缺点:第一次进行创建的时候效率会比较低
 4  */
 5 public class SingleInstance04 {
 6     private volatile static SingleInstance04 instance04;
 7     /**
 8      * 记住:单例都要私有化构造函数的;不要问为什么,自己想想哦
 9      */
10     private SingleInstance04() {}
11 
12     public static SingleInstance04 getInstance(){
13         if (instance04 == null){//第一次判断是空开启锁
14             synchronized (SingleInstance04.class){
15                 if(instance04 == null){//第二次判断空开始创建对像   为什么第2次还要判断空?考虑多线程,具体原因不述
16                     instance04=new SingleInstance04();
17                 }
18             }
19         }
20         return instance04;
21     }
22 }

 5、静态内部模式

public class SingletonV5 {

    private SingletonV5() {
        System.out.println("对象初始...");
    }

    public static SingletonV5 getInstance() {
        return SingletonV5Utils.singletonV5;
    }

    /**
     * 静态内部方式能够避免同步带来的效率问题和有能实现延迟加载
   * 继承了懒汉式的优点,同时解决双重校验锁的第一次加载慢的的问题
*/ public static class SingletonV5Utils { private static SingletonV5 singletonV5 = new SingletonV5(); } public static void main(String[] args) { System.out.println("项目启动成功"); SingletonV5 instance1 = SingletonV5.getInstance(); SingletonV5 instance2 = SingletonV5.getInstance(); System.out.println(instance1 == instance2); } }

6、枚举式

public enum EnumSingleton {
    INSTANCE;

    // 枚举能够绝对有效的防止实例化多次,和防止反射和序列化破解
    public void add() {
        System.out.println("add方法...");
    }
}

public static void main(String[] args) throws Exception {
    EnumSingleton instance1 = EnumSingleton.INSTANCE;
    EnumSingleton instance2 = EnumSingleton.INSTANCE;
    System.out.println(instance1 == instance2);
    Constructor<EnumSingleton> declaredConstructor = EnumSingleton.class.getDeclaredConstructor();
    declaredConstructor.setAccessible(true);
    EnumSingleton v3 = declaredConstructor.newInstance();
    System.out.println(v3==instance1);
}

通过反射和序列化技术破坏单例  

  // 1.反射破坏单例: 使用懒汉式创建对象

  SingletonV3 instance1 = SingletonV3.getInstance();
  // 2. 使用Java反射技术初始化对象 执行无参构造函数
  
Constructor<SingletonV3> declaredConstructor = SingletonV3.class.getDeclaredConstructor();
  declaredConstructor.setAccessible(true);
  SingletonV3 instance2 = declaredConstructor.newInstance();
  System.out.println(instance1 == instance2);

 -------------------------------------------

 //可以通过私有化构造数函数防止

private SingletonV3() throws Exception {
    synchronized (SingletonV3.class) {
        if (singletonV3 != null) {
            throw new Exception("该对象已经初始化..");
        }
        System.out.println("执行SingletonV3无参构造函数...");
    }

}

--------------------------------
//使用序列化破坏单例
Singleton instance = Singleton.getInstance(); FileOutputStream fos = new FileOutputStream("E:\\code\\Singleton.obj"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(instance); oos.flush(); oos.close(); FileInputStream fis = new FileInputStream("E:\\code\\Singleton.obj"); ObjectInputStream ois = new ObjectInputStream(fis); Singleton singleton2 = (Singleton) ois.readObject(); System.out.println(singleton2==instance)

 

posted on 2020-02-21 16:29  JAVA-ROAD  阅读(129)  评论(0)    收藏  举报

导航