当前位置: 移动技术网 > IT编程>软件设计>设计模式 > 单例模式学习

单例模式学习

2020年04月28日  | 移动技术网IT编程  | 我要评论

单例模式学习

1 饿汉式单例模式

package main.java.com.yuehun.singleton;

/**
 * main.java.com.yuehun.singleton
 *
 * @author yuehun
 * created on 2020/4/27.
 */

// 饿汉式单例模式
public class hungry {
    private hungry(){}

    private final static hungry hungry = new hungry();

    public static hungry getinstance()
    {
        return hungry;
    }
}
  • 还没用就创建了对象,可能会浪费空间

2 懒汉式单例模式

无线程锁

package main.java.com.yuehun.singleton;

/**
 * main.java.com.yuehun.singleton
 *
 * @author yuehun
 * created on 2020/4/27.
 */

// 懒汉式单例模式
public class lazy {
    private lazy(){
        system.out.println(thread.currentthread().getname() + "ok");
    }

    private static lazy lazy = null;

    public static lazy getinstance()
    {
        if (lazy == null)
        {
            lazy = new lazy();
        }
        return lazy;
    }

    public static void main(string[] args) {
        for (int i = 0; i < 10; i++)
        {
            new thread(lazy::getinstance).start();
        }
    }
}
  • 单线程下可以,但是多线程不安全

加线程锁

package main.java.com.yuehun.singleton;

/**
 * main.java.com.yuehun.singleton
 *
 * @author yuehun
 * created on 2020/4/27.
 */

// 懒汉式单例模式
public class lazy {
    private lazy(){
        system.out.println(thread.currentthread().getname() + " ok");
    }

    private volatile static lazy lazy = null;

    // 双重检测锁模式的懒汉式单例模式, dcl 懒汉式
    public static lazy getinstance()
    {
        if (lazy == null) {
            synchronized (lazy.class) {
                if (lazy == null) {
                    lazy = new lazy(); // 不是一个原子性操作
                    /**
                     * 1 分配内存空间
                     * 2 执行构造方法,初始化对象
                     * 3 把这个对象指向这个空间
                     *
                     * 可能会发生指令重排!!!
                     */
                }
            }
        }
        return lazy;
    }

    public static void main(string[] args) {
        for (int i = 0; i < 10; i++)
        {
            new thread(lazy::getinstance).start();
        }
    }
}

3 单例不是安全的

使用反射破坏单例模式

  • java 里面有个东西叫反射
  • 比如:
package main.java.com.yuehun.singleton;

import java.lang.reflect.constructor;

/**
 * main.java.com.yuehun.singleton
 *
 * @author yuehun
 * created on 2020/4/27.
 */

// 饿汉式单例模式
public class hungry {
    private hungry(){}

    private final static hungry hungry = new hungry();

    public static hungry getinstance()
    {
        return hungry;
    }

    public static void main(string[] args) throws exception {
        hungry instance = new hungry();

        constructor<hungry> declaredconstructor = hungry.class.getdeclaredconstructor(null);
        declaredconstructor.setaccessible(true);
        hungry instance2 = declaredconstructor.newinstance();

        system.out.println(instance);
        system.out.println(instance2);
    }
}

阻止反射破坏

阻止反射的破坏

package main.java.com.yuehun.singleton;

import java.lang.reflect.constructor;

/**
 * main.java.com.yuehun.singleton
 *
 * @author yuehun
 * created on 2020/4/27.
 */

// 饿汉式单例模式
public class hungry {
    private hungry(){
        synchronized (hungry.class)
        {
            if (hungry != null)
            {
                throw new runtimeexception("不要试图使用反射破坏单例模式");
            }
        }
    }

    private final static hungry hungry = new hungry();

    public static hungry getinstance()
    {
        return hungry;
    }

    public static void main(string[] args) throws exception {
        hungry instance = new hungry();

        constructor<hungry> declaredconstructor = hungry.class.getdeclaredconstructor(null);
        declaredconstructor.setaccessible(true);
        hungry instance2 = declaredconstructor.newinstance();

        system.out.println(instance);
        system.out.println(instance2);
    }
}

还有一种反射破坏

  • 如果两个对象都是通过反射构造的,就不会触发异常
package main.java.com.yuehun.singleton;

import java.lang.reflect.constructor;

/**
 * main.java.com.yuehun.singleton
 *
 * @author yuehun
 * created on 2020/4/27.
 */

// 懒汉式单例模式
public class lazy {
//    private static boolean flag = false;

    private lazy()
    {
        synchronized (lazy.class)
        {
//            if (!flag)
//                flag = true;
//            else {
                if (lazy != null) {
                    throw new runtimeexception("不要试图使用反射破坏单例模式");
//                }
            }
        }
    }

    private volatile static lazy lazy = null;

    // 双重检测锁模式的懒汉式单例模式, dcl 懒汉式
    public static lazy getinstance()
    {
        if (lazy == null)
        {
            synchronized (lazy.class)
            {
                if (lazy == null)
                {
                    lazy = new lazy(); // 不是一个原子性操作
                    /**
                     * 1 分配内存空间
                     * 2 执行构造方法,初始化对象
                     * 3 把这个对象指向这个空间
                     *
                     * 可能会发生指令重排!!!
                     */
                }
            }
        }
        return lazy;
    }

    public static void main(string[] args) throws exception
    {
        constructor<lazy> declaredconstructor = lazy.class.getdeclaredconstructor(null);
        declaredconstructor.setaccessible(true);
        lazy instance = declaredconstructor.newinstance();
        lazy instance2 = declaredconstructor.newinstance();

        system.out.println(instance);
        system.out.println(instance2);
    }
}

又有一种解决方法

package main.java.com.yuehun.singleton;

import java.lang.reflect.constructor;

/**
 * main.java.com.yuehun.singleton
 *
 * @author yuehun
 * created on 2020/4/27.
 */

// 懒汉式单例模式
public class lazy {
    private static boolean flag = false;

    private lazy()
    {
        synchronized (lazy.class)
        {
            if (!flag)
                flag = true;
            else
                throw new runtimeexception("不要试图使用反射破坏单例模式");
        }
    }

    private volatile static lazy lazy = null;

    // 双重检测锁模式的懒汉式单例模式, dcl 懒汉式
    public static lazy getinstance()
    {
        if (lazy == null)
        {
            synchronized (lazy.class)
            {
                if (lazy == null)
                {
                    lazy = new lazy(); // 不是一个原子性操作
                    /**
                     * 1 分配内存空间
                     * 2 执行构造方法,初始化对象
                     * 3 把这个对象指向这个空间
                     *
                     * 可能会发生指令重排!!!
                     */
                }
            }
        }
        return lazy;
    }

    public static void main(string[] args) throws exception
    {
        constructor<lazy> declaredconstructor = lazy.class.getdeclaredconstructor(null);
        declaredconstructor.setaccessible(true);
        lazy instance = declaredconstructor.newinstance();
        lazy instance2 = declaredconstructor.newinstance();

        system.out.println(instance);
        system.out.println(instance2);
    }
}

破坏者又来了

  • 可以通过反射获取到我们设置的这个标志位,在以后每一次创建对象的时候修改它
package main.java.com.yuehun.singleton;

import java.lang.reflect.constructor;
import java.lang.reflect.field;

/**
 * main.java.com.yuehun.singleton
 *
 * @author yuehun
 * created on 2020/4/27.
 */

// 懒汉式单例模式
public class lazy {
    private static boolean flag = false;

    private lazy()
    {
        synchronized (lazy.class)
        {
            if (!flag)
                flag = true;
            else
                throw new runtimeexception("不要试图使用反射破坏单例模式");
        }
    }

    private volatile static lazy lazy = null;

    // 双重检测锁模式的懒汉式单例模式, dcl 懒汉式
    public static lazy getinstance()
    {
        if (lazy == null)
        {
            synchronized (lazy.class)
            {
                if (lazy == null)
                {
                    lazy = new lazy(); // 不是一个原子性操作
                    /**
                     * 1 分配内存空间
                     * 2 执行构造方法,初始化对象
                     * 3 把这个对象指向这个空间
                     *
                     * 可能会发生指令重排!!!
                     */
                }
            }
        }
        return lazy;
    }

    public static void main(string[] args) throws exception
    {
        field flag = lazy.class.getdeclaredfield("flag");
        flag.setaccessible(true);

        constructor<lazy> declaredconstructor = lazy.class.getdeclaredconstructor(null);
        declaredconstructor.setaccessible(true);

        lazy instance = declaredconstructor.newinstance();
        
        flag.set(instance, false);
        lazy instance2 = declaredconstructor.newinstance();

        system.out.println(instance);
        system.out.println(instance2);
    }
}

道高一尺,魔高一丈

4 枚举解决

  • enum 本身也是一个 class 类
package main.java.com.yuehun.singleton;

import java.lang.reflect.constructor;

/**
 * main.java.com.yuehun.singleton
 *
 * @author yuehun
 * created on 2020/4/27.
 */
public enum enumsingleton {
    instance;

    public enumsingleton getinstance()
    {
        return instance;
    }
}

class test {
    public static void main(string[] args) throws exception {
        enumsingleton instance1 = enumsingleton.instance;

        constructor<enumsingleton> declaredconstructor = enumsingleton.class.getdeclaredconstructor(string.class, int.class);
        declaredconstructor.setaccessible(true);
        enumsingleton instance2 = declaredconstructor.newinstance();

        system.out.println(instance1);
        system.out.println(instance2);
    }
}

到此,阻止反射破坏就成功了!

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网