单例模式(饿汉式单例和懒汉式单例以及内部类实现)

饿汉式单例

package com.hua.DesignPatterns.single;


/*
* 饿汉式单例,一上来就创建对象,浪费内存
*
* */
public class Hungry {
    private byte[] data1=new byte[1024*1024];
    private byte[] data2=new byte[1024*1024];
    private byte[] data3=new byte[1024*1024];
    private byte[] data4=new byte[1024*1024];
    private Hungry(){

    }
    private static final Hungry HUNGRY=new Hungry();
    public static Hungry getInstance(){
        return HUNGRY;
    }

}

懒汉式单例


package com.hua.DesignPatterns.single;

public class LazyMan1 {

    private LazyMan1(){
        System.out.println(Thread.currentThread().getName()+"ok");
    }
    private static LazyMan1 LAZYMAN1=null;

    public static LazyMan1 getInstance(){
        /**
         *  因为getInstance方法没有加锁,多个线程能同时进入这个方法
         *  导致多个线程能同时进入到LAZYMAN1=new LazyMan1();
         *  所以单例模式会被破坏
         */
        if (LAZYMAN1==null){
            LAZYMAN1=new LazyMan1();
            return LAZYMAN1;
        }
        return LAZYMAN1;
    }

    public static void main(String[] args) {

        for (int i=0;i<10;i++){
            new Thread(()->{
         LazyMan1 lazyMan1=LazyMan1.getInstance();
            }).start();
        }
    }
}

运行结果
在这里插入图片描述
解决办法:双重检测锁模式

package com.hua.DesignPatterns.single;

public class LazyMan1 {

    private LazyMan1(){
        System.out.println(Thread.currentThread().getName()+"ok");
    }
    private static LazyMan1 LAZYMAN1=null;

    public static LazyMan1 getInstance(){
        /**
         *  双重检测锁模式 首先判断LAZYMAN1是否为空,为空的话,加一把类锁
         *  然后在同步代码块里面再次判断判断LAZYMAN1是否为空,
         *  如果为空的话就new一个对象
         */
        if (LAZYMAN1==null){
            synchronized (LazyMan1.class){
                if (LAZYMAN1==null){
                    LAZYMAN1=new LazyMan1();
                }
            }
        }

        return LAZYMAN1;
    }

    public static void main(String[] args) {

        for (int i=0;i<10;i++){
            new Thread(()->{
         LazyMan1 lazyMan1=LazyMan1.getInstance();
            }).start();
        }
    }
}

双重检测锁模式下可能出现的问题

package com.hua.DesignPatterns.single;

public class LazyMan1 {

    private LazyMan1(){
        System.out.println(Thread.currentThread().getName()+"ok");
    }
    private static volatile LazyMan1 LAZYMAN1=null;

    public static LazyMan1 getInstance(){

        if (LAZYMAN1==null){
            synchronized (LazyMan1.class){
                if (LAZYMAN1==null){
                    /*
                     * 不是原子性操作,分三步
                     * 1.分配内存空间
                     * 2.使用构造函数初始化对象
                     * 3.把 LAZYMAN1指向初始化后的空间
                     * 正常的执行顺序是 123
                     * 由于指令重排可能导致 132的执行顺序,当执行到13的时候 另一个线程进入到这个函数
                     * 判断LAZYMAN1 不等于空,这时就直接返回LAZYMAN1,然而LAZYMAN1还没有初始化
                     * 这时候就会产生问题
                     * 解决方式 在LAZYMAN1 前加 volatile 修饰
                     * */
                    LAZYMAN1=new LazyMan1();
                }
            }
        }

        return LAZYMAN1;
    }

    public static void main(String[] args) {

        for (int i=0;i<10;i++){
            new Thread(()->{
         LazyMan1 lazyMan1=LazyMan1.getInstance();
            }).start();
        }
    }
}

静态内部类实现

package com.hua.DesignPatterns.single;
/*静态内部类实现*/
public class Holder {

    private Holder(){

    }
    public static Holder getInstance(){
        return InnerClass.HOLDER;
    }
    public static class InnerClass{
      public static final Holder HOLDER=new Holder();
    }
}

反射可以破坏单例
解决办法:在构造函数中设置一个同步代码块,然后在类中设置一个标志位,如果第一次进入构造函数就正确通过,其他的就抛出一个异常

package com.hua.DesignPatterns.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class LazyMan1 {
    
    public static boolean just=false;
    
    private LazyMan1(){
            synchronized (LazyMan1.class){
                if (just==false){
                    just=true;
                    System.out.println("生成单例对象");
                }else{
                    throw new RuntimeException("不要试图用反射破坏异常");
                }
    }
        System.out.println(Thread.currentThread().getName()+"ok");
    }
    private static volatile LazyMan1 LAZYMAN1=null;

    public static LazyMan1 getInstance(){

        if (LAZYMAN1==null){
            synchronized (LazyMan1.class){
                if (LAZYMAN1==null){
                    /*
                     * 不是原子性操作,分三步
                     * 1.分配内存空间
                     * 2.使用构造函数初始化对象
                     * 3.把 LAZYMAN1指向初始化后的空间
                     * 正常的执行顺序是 123
                     * 由于指令重排可能导致 132的执行顺序,当执行到13的时候 另一个线程进入到这个函数
                     * 判断LAZYMAN1 不等于空,这时就直接返回LAZYMAN1,然而LAZYMAN1还没有初始化
                     * 这时候就会产生问题
                     * 解决方式 在LAZYMAN1 前加 volatile 修饰
                     * */
                    LAZYMAN1=new LazyMan1();
                }
            }
        }

        return LAZYMAN1;
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        Constructor<LazyMan1> declaredConstructor = LazyMan1.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyMan1 man1 = declaredConstructor.newInstance();
        LazyMan1 man2 = declaredConstructor.newInstance();
        System.out.println(man1==man2);
    }
}

运行结果
在这里插入图片描述
枚举:

package com.hua.DesignPatterns.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

//enum
public enum EnumSingle {
     INSTANCE;
     public static EnumSingle getInstance(){
         return INSTANCE;
     }
}
class Test{
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        EnumSingle single1=EnumSingle.getInstance();
        EnumSingle single2=EnumSingle.getInstance();
        System.out.println(single1==single2);
        Constructor<EnumSingle> constructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        constructor.setAccessible(true);
        EnumSingle single3 = constructor.newInstance();
        System.out.println(single1==single3);
    }
}

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值