美文网首页
高并发下线程安全的单例模式

高并发下线程安全的单例模式

作者: JackEason | 来源:发表于2019-05-17 09:57 被阅读0次

    1.饿汉式

    实现代码:

    public class MySingleton {

      // 1.饿汉式

      private static MySingleton singleton = new  MySingleton();

      private MySingleton() {

      }

      public static MySingleton getInstance() {

        return singleton;

      }

    }

    开启多线程进行测试:

    public class SingletonMain extends Thread {

      @Override

      public void run() {

         System.out.println(MySingleton.getInstance().hashCode());

      }

      public static void main(String[] args) {

        // 创建多线程,一起执行看是否生成同一对象

        SingletonMain th1 = new SingletonMain();

        SingletonMain th2 = new SingletonMain();

        SingletonMain th3 = new SingletonMain();

        th1.start();

        th2.start();

        th3.start();

      }

    }

    结果:

    477037219

    477037219

    477037219

    结论:hashCode值一致,说明是同一对象,饿汉式单例模式线程安全

    2.懒汉式

    实现代码

    public class MySingleton {

      // 2.懒汉式

      private static MySingleton instance = null;

      private MySingleton() {

      }

      public static MySingleton getInstance() throws  InterruptedException {

        if (instance == null) {

          // 创建实例之前可能会有一些准备性的耗时工作

          Thread.sleep(300);

          instance = new MySingleton();

        }

        return instance;

      }

    }

    开启多线程进行测试,

    public class SingletonMain extends Thread {

      @Override

      public void run() {

        try {

           System.out.println(MySingleton.getInstance().hashCode());

        } catch (InterruptedException e) {

          e.printStackTrace();

        }

      }

      public static void main(String[] args) {

        // 创建多线程,一起执行看是否生成同一对象

        SingletonMain th1 = new SingletonMain();

        SingletonMain th2 = new SingletonMain();

        SingletonMain th3 = new SingletonMain();

        th1.start();

        th2.start();

        th3.start();

      }

    }

    结果

    1891072390

    1139700714

    477037219

    结论:

    不同线程输出的hashCode值不一致,对象不同,懒汉式单例模式线程不安全。

    造成不安全的原因:多个线程在进入getInstance方法时,都并没有对象创建出来,导致所有线程都符合(instance == null)的条件,导致对象被重复创建,不构成单例的前提

    2-01. 懒汉式改良版-静态同步函数实现

    实现代码,增加synchronized关键词,静态同步函数实现线程安全

    public class MySingleton {

      // 2.懒汉式

      private static MySingleton instance = null;

      private MySingleton() {

      }

      public static synchronized MySingleton getInstance()  throws InterruptedException {

        if (instance == null) {

          // 创建实例之前可能会有一些准备性的耗时工作

          Thread.sleep(300);

          instance = new MySingleton();

        }

        return instance;

      }

    }

    结果

    1891072390

    1891072390

    1891072390

    结论:

    静态同步函数可以实现懒汉式单例模式的线程安全,但是将一整个方法都进行加锁,会导致此方法的运行效率降低,继续考虑其他方式进行改良

    2-02.  懒汉式改良版-同步代码块实现

    实现代码:增加synchronized关键词,对指定代码块加锁,可以大大的提高整个方法的执行效率,下面使用同步代码块实现

    public class MySingleton {

      // 2.懒汉式

      private static MySingleton instance = null;

      private MySingleton() {

      }

      public static MySingleton getInstance() throws  InterruptedException {

        if (instance == null) {

          // 创建实例之前可能会有一些准备性的耗时工作

          Thread.sleep(300);

          synchronized (MySingleton.class) {

            instance = new MySingleton();

          }

        }

        return instance;

      }

    }

    结果

    1891072390

    756680587

    1994444141

    结论:目前此种调整方式还不能达到线程安全,继续改良

    双检查锁机制

    实现代码

    public class MySingleton {

      // 2.懒汉式

      private static MySingleton instance = null;

      private MySingleton() {

      }

      public static MySingleton getInstance() throws  InterruptedException {

        if (instance == null) {

          // 创建实例之前可能会有一些准备性的耗时工作

          Thread.sleep(300);

          synchronized (MySingleton.class) {

            if (instance == null) {

              instance = new MySingleton();

            }

          }

        }

        return instance;

      }

    }

    结果:

    1994444141

    1994444141

    1994444141

    结论:

    双检查锁机制可以实现懒汉式单例模式的线程安全,而且这种方式的效率相对于第一种来说是比较高的

    3.静态内置类实现单例模式

    实现代码

    public class MySingleton {

      private static class MySingletonHandler {

        private static MySingleton singleon = new  MySingleton();

      }

      public static MySingleton getInstance() {

        return MySingletonHandler.singleon;

      }

    }

    开启多线程测试

    public class SingletonMain extends Thread {

      @Override

      public void run() {

         System.out.println(MySingleton.getInstance().hashCode());

      }

      public static void main(String[] args) {

        // 创建多线程,一起执行看是否生成同一对象

        SingletonMain th1 = new SingletonMain();

        SingletonMain th2 = new SingletonMain();

        SingletonMain th3 = new SingletonMain();

        th1.start();

        th2.start();

        th3.start();

      }

    }

    结果

    1740545285

    1740545285

    1740545285

    结论:

    静态内置类实现单例模式是线程安全的

    4.静态代码块实现单例模式

    实现代码:静态代码块中的代码在使用类的时候就已经执行了,所以可以应用静态代码块的这个特性的实现单例设计模式。

    public class MySingleton {

      // 使用静态代码块实现单例模式

      private static MySingleton singleon = null;

      private MySingleton() {}

      static {

        singleon = new MySingleton();

      }

      public static MySingleton getInstance() {

        return singleon;

      }

    }

    结果

    1209285429

    1209285429

    1209285429

    结论:静态代码块只在类加载时执行,因而只有一个实体对象,从结果来看,线程也是安全的

    5.使用枚举数据类型实现单例模式

    实现代码

    public class ClassFactory {

      private enum MyEnumSingleton {

        singletonFactory;

        private MySingleton instance;

        private MyEnumSingleton() {// 枚举类的构造方法在类加载是被实例化

          instance = new MySingleton();

        }

        public MySingleton getInstance() {

          return instance;

        }

      }

      public static MySingleton getInstance() {

        return MyEnumSingleton.singletonFactory.getInstance();

      }

    }

    结果

    1139700714

    1139700714

    1139700714

    结论:枚举实现单例模式是线程安全的

    相关文章

      网友评论

          本文标题:高并发下线程安全的单例模式

          本文链接:https://www.haomeiwen.com/subject/pdweuqtx.html