设计模式——单例模式

单例设计模式

作用:

保证一个类只有一个对象,并且提供一个访问该实例的全局访问点

常见场景:

  • windows中任务管理器
  • Windows中回收站
  • 网站计数器
  • 日志应用
  • 数据库连接池
  • 操作系统的文件系统
  • Application(Servlet)
  • Spring中的每个bean默认是单例
  • SpringMVC中控制器也是单例的

单例模式的优点:

单例模式只生成一个实例,减少系统性能的开销,当一个对象产生多的资源时,读取配置,产生其他对象时,需要在应用启动时
直接产生一个单例对象,永久保存在内存中的方式解决。

单例模式的主要分类:

  • 饿汉单例(线程安全,调用率高,不能够延迟加载);
  • 懒汉单例(线程安全,调用效率不高,可以延迟加载);
  • 双重检测锁式(由于JVM底层内部模型原因,偶尔出问题,不建议使用);
  • 静态内部类式(线程安全,调用效率高,可以延迟加载);
  • 枚举单例(线程安全,调用效率高,不能延迟加载);
饿汉
package com.wangpx.design;


/**
 * 饿汉式单例模式
 * @author wangpx
 *
 */
public class Singleton {
    //类初始化时立即加载,线程安全
    private static Singleton singleton = new Singleton();
    private Singleton() {};

    //方法没有同步,效率高
    public static Singleton getInstance() {
        return singleton;
    }
}
懒汉
package com.wangpx.design;

/**
 *
 * 懒汉单例模式
 * 延迟加载,真正用的时候才使用 对象懒加载
 * @author wangpx
 */
public class Singleton2 {

    private static Singleton2 singleton2;

    private Singleton2 () {};

    //同步方法  并发效率低
    public static synchronized Singleton2 getInstance() {
        if (singleton2 == null) {
            singleton2 = new Singleton2();
        }
        return singleton2;
    }
}

双重检查锁
package com.wangpx.design;

/**
 *
 * 双重检查锁单例模式
 * 提高了执行效率,不必每次获取对象时都进行同步,只有第一次才同步创建后就没有必要了
 * @author wangpx
 */
public class Singleton3 {

    private static Singleton3 singleton3 = null;

    private Singleton3() {};

    public static synchronized Singleton3 getInstance() {

        if (singleton3 == null) {
            Singleton3 singleton31;
            synchronized (Singleton3.class) {
                singleton31 = singleton3;
                if (singleton31 == null) {
                    synchronized (Singleton3.class) {
                        if (singleton31 == null) {
                            singleton31 = new Singleton3();
                        }
                    }
                    singleton3 = singleton31;
                }
            }
        }

        return singleton3;
    }
}

静态内部类
package com.wangpx.design;

/**
 *
 * 静态内部类单例模式
 * @author wangpx
 */
public class Singleton4 {

    private Singleton4() {}

    /**
     * 内部类没有static属性,不会像饿汉模式类初始化时加载对象
     * 只有调用getInstance()才会加载静态内部类
     * 线程安全,instance是 static final类型,保证内存中只有一个实例,只能赋值一次
     * 并发高效调用  延迟加载
     */
    private static class SingletonClassInstance {
        private static final Singleton4 instance = new Singleton4();
    }

    public static Singleton4 getInstance() {
        return SingletonClassInstance.instance;
    }

}

枚举类型
package com.wangpx.design;

/**
 *
 * 枚举单例模式
 * 没有延迟加载
 * 防止反射和反序列化漏洞
 * @author wangpx
 */
public enum  Singleton5 {

    /**
     * 定义一个枚举元素,代表一个Singleton实例,本身单例
     */
    INSTANCE;
    public void singletonOperation() {
        //功能实现
    }

}

反射和反序列化漏洞的解决方案

package com.wangpx.design;

import java.io.ObjectStreamException;
import java.io.Serializable;

/**
 *
 * 防止反射和反序列化漏洞
 * @author wangpx
 */
public class Singleton6 implements Serializable {

    private static Singleton6 singleton6;

    private Singleton6() {
        if (singleton6 != null) {
            throw new RuntimeException();
        }
    };


    //同步方法  并发效率低
    public static synchronized Singleton6 getInstance() {
        if (singleton6 == null) {
            singleton6 = new Singleton6();
        }
        return singleton6;
    }


    /**
     * 反序列化时,直接调用readResolve()方法,返回此方法指定对象,不需要再次创建新对象
     * @return
     * @throws ObjectStreamException
     */
    private Object readResolve () throws ObjectStreamException {
        return singleton6;
    }
}

package com.wangpx.test;

import com.wangpx.design.Singleton6;

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

public class Test2 implements Serializable {

    public static void main(String[] args) {

        Singleton6 instance = Singleton6.getInstance();
        System.out.println(instance);

        /**
         * 通过反射的方式破解单例模式调用私有构造器
         */
       /* try {
            Class<Singleton6> clazz = (Class<Singleton6>) Class.forName("com.wangpx.design.Singleton6");
            Constructor<Singleton6> constructor = clazz.getDeclaredConstructor(null);
            constructor.setAccessible(true);
            Singleton6 s1 = constructor.newInstance();
            Singleton6 s2 = constructor.newInstance();
            System.out.println(s1 == s2);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }*/
        /**
         * 通过反序列化构建多个对象
         *
         */
        FileOutputStream fos =null ;
        ObjectOutputStream oos = null;
        try {
            fos= new FileOutputStream("d:/wangpx.log");
            oos = new ObjectOutputStream(fos);
            oos.writeObject(instance);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fos.close();
                oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        ObjectInputStream ois = null;

        try {
            ois = new ObjectInputStream(new FileInputStream("d:/wangpx.log"));
            Singleton6 singleton6 = (Singleton6) ois.readObject();
            System.out.println(singleton6);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

测试执行效率
package com.wangpx.test;

import com.wangpx.design.*;

import java.util.concurrent.CountDownLatch;

/**
 * 测试五种单例模式的效率
 */
public class Test3 {

    public static void main(String[] args) throws InterruptedException {
        /**
         * 饿汉
         */
        long start = System.currentTimeMillis();
        int threadNum = 10;
        final CountDownLatch countDownLatch = new CountDownLatch(threadNum);
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 1000000; i++) {
                        //
                        // Singleton4 instance = Singleton4.getInstance();
                        Object o= Singleton5.INSTANCE;
                    }
                    countDownLatch.countDown();
                }
            }).start();
        }
        //main线程阻塞,直到计数器为0,才会往下执行
        countDownLatch.await();
        long end = System.currentTimeMillis();
        System.out.println("总耗时:"+(end-start)+"ms");
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值