zoukankan      html  css  js  c++  java
  • Java设计模式之--单例模式-使用懒汉模式创建

    一、这是在单线程的情况下创建的
    package com.sinosoft.test;

    import javax.jnlp.SingleInstanceListener;

    /**
    *
    */
    public class SingletonTest {
    public static void main(String[] args) {
    //可见这种方法就创建不了了
    // LazySingleton lazySingleton=new LazySingleton();
    LazySingleton lazySingleton = LazySingleton.getInstance();
    }


    }

    //使用的时候才开始初始化,jvm运行的整个期间都只有一个实例
    class LazySingleton {
    private static LazySingleton instance;

    public static LazySingleton getInstance() {
    if (instance == null) {
    instance = new LazySingleton();
    }
    return instance;
    }

    //将new 对象的构造方法屏蔽掉,不允许在外部进行多次创建
    private LazySingleton() {

    }

    }

    二、多线程场景下
    package com.sinosoft.test;

    import javax.jnlp.SingleInstanceListener;
    import java.sql.Time;
    import java.util.concurrent.TimeUnit;

    /**
    *
    */
    public class SingletonTest {
    public static void main(String[] args) {
    //可见这种方法就创建不了了
    // LazySingleton lazySingleton=new LazySingleton();


    //下面我们验证一下在多线程的情况下看看会不会创建多个实例
    new Thread(new Runnable() {
    @Override
    public void run() {
    LazySingleton lazySingleton = LazySingleton.getInstance();
    //通过打印他的内存地址来进行验证
    System.out.println("============" + lazySingleton);
    }
    }).start();
    new Thread(new Runnable() {
    @Override
    public void run() {
    LazySingleton lazySingleton = LazySingleton.getInstance();
    //通过打印他的内存地址来进行验证
    System.out.println("============" + lazySingleton);
    }
    }).start();
    }


    }

    //使用的时候才开始初始化,jvm运行的整个期间都只有一个实例
    class LazySingleton {
    private static LazySingleton instance;

    public static LazySingleton getInstance() {
    try {
    if (instance == null) {
    // 主要是模拟高并发场景下线程之间的调度
    TimeUnit.MILLISECONDS.sleep(1200);
    instance = new LazySingleton();
    }
    } catch (InterruptedException ex) {
    ex.printStackTrace();
    }

    return instance;
    }

    //将new 对象的构造方法屏蔽掉,不允许在外部进行多次创建
    private LazySingleton() {

    }

    }

    运行结果:
    我们可以看到创建了两个实例:

    ============com.sinosoft.test.LazySingleton@606232e4
    ============com.sinosoft.test.LazySingleton@7c60d4cb

    出现这种情况的原因是:在同一时刻有两个线程在同时访问这个方法。怎样避免,我们可以将synchronized关键字,让同一时刻只能有一个线程进行访问。

    //使用的时候才开始初始化,jvm运行的整个期间都只有一个实例
    class LazySingleton {
    private static LazySingleton instance;

    public static synchronized LazySingleton getInstance() {
    try {
    if (instance == null) {
    // 主要是模拟高并发场景下线程之间的调度
    TimeUnit.MILLISECONDS.sleep(1200);
    instance = new LazySingleton();
    }
    } catch (InterruptedException ex) {
    ex.printStackTrace();
    }

    return instance;
    }

    //将new 对象的构造方法屏蔽掉,不允许在外部进行多次创建
    private LazySingleton() {

    }

    运行结果:

    ============com.sinosoft.test.LazySingleton@606232e4
    ============com.sinosoft.test.LazySingleton@606232e4

    其实上面这种加锁的方式是比较重的一种方法,固定死了一次就只能有一个线程进行访问,不利于高并发场景。

    解决这种问题,我们可以使用双重校验(或者叫双重锁)

    //使用的时候才开始初始化,jvm运行的整个期间都只有一个实例
    class LazySingleton {
    private static LazySingleton instance;

    public static LazySingleton getInstance() {
    try {
    if (instance == null) {
    // 主要是模拟高并发场景下线程之间的调度
    synchronized (LazySingleton.class) {
    if (instance == null) {
    instance = new LazySingleton();
    }
    }
    }
    } catch (Exception ex) {
    ex.printStackTrace();
    }

    return instance;
    }

    //将new 对象的构造方法屏蔽掉,不允许在外部进行多次创建
    private LazySingleton() {

    }

    运行结果:

    ============com.sinosoft.test.LazySingleton@52a17671
    ============com.sinosoft.test.LazySingleton@52a17671

    当然为了防止jvm指令重排序,我们加上volatile关键字进行修饰:

    private static volatile LazySingleton instance;

    三、使用静态内部类进行单例模式的创建,这也是懒汉模式的一种实现方式
    package com.sinosoft.test;

    /**
    * 这是通过静态内的方式实现单例模式,也是懒加载的一种实现方式
    */
    public class InnerClassSingleton {
    static class InnerClass{
    private static InnerClassSingleton instance=new InnerClassSingleton();
    }
    //这是提供给外部进行访问和创建单例的方法
    public static InnerClassSingleton getInstance(){
    return InnerClass.instance;
    }

    private InnerClassSingleton(){

    }
    }

    接下来,我们通过反射机制来破坏单例类的创建
    package com.sinosoft.test;

    import java.lang.reflect.Constructor;

    /**
    * 接下来,我们对我们创建的单例类通过反射的机制进行破坏,也就是说创建多个实例
    */
    public class Anti {
    public static void main(String[] args) {
    try{
    //使用反射的机制获取实例
    Constructor<InnerClassSingleton> declaredConstructor = InnerClassSingleton.class.getDeclaredConstructor();
    declaredConstructor.setAccessible(true);
    InnerClassSingleton innerClassSingleton = declaredConstructor.newInstance();

    //使用静态内部类的方式获取实例
    InnerClassSingleton instance = InnerClassSingleton.getInstance();

    System.out.println(innerClassSingleton==instance);
    }catch (Exception e){
    e.printStackTrace();
    }

    }
    }
    运行结果:

    false

    我们能够发现,我们创建了两个不同的实例,这种情况下,我们应该怎样解决呢,答案很简单。

     再次运行程序:

  • 相关阅读:
    PHP 的 序列化与反序列化 自己的理解
    通达OA 11.6 rce漏洞复现
    MySQL 表字段唯一性约束设置方法unique
    HTTP响应状态码
    PHP 魔术变量
    PHP匿名函数使用技巧
    PHP 三大结构
    PHP unset()函数销毁变量
    算法第五章作业
    算法第四章作业
  • 原文地址:https://www.cnblogs.com/dongyaotou/p/13568771.html
Copyright © 2011-2022 走看看