java设计模式之单例模式,单例模式 java实现

  java设计模式之单例模式,单例模式 java实现

  00-1010序懒单例懒单例非线程安全的懒单例加同步锁懒单例双检懒单例静态内部类为什么静态内部类是线程安全的摘要?

  00-1010单例模式是Java中最简单的设计模式之一。这种类型的设计模式属于创造性模式,它提供了创建对象的最佳方式。

  这种模式涉及一个单独的类,它负责创建自己的对象,同时确保只创建一个对象。该类提供了访问其唯一对象的方法,可以直接访问该对象,而无需实例化该类的对象。

  是否多线程安全:是的。

  是否懒加载:没有。

  顾名思义,饿汉需要直接创建一个实例。

  公共类EhSingleton {私有静态EhSingleton EhSingleton=new EhSingleton();private EhSingleton(){ } public static EhSingleton getInstance(){ return EhSingleton;}}缺点:类在加载的时候就初始化了,浪费内存。

  优点:无锁,执行效率高。或者线程安全的实例。

  00-1010 Lazy singleton,类初始化时不会创建实例,只有调用时才会创建实例。

  00-1010是否多线程安全:号

  是否懒加载:是的。

  public类LazySingleton { private static LazySingleton ehSingleton;private LazySingleton(){ } public static LazySingleton getInstance(){ if(ehSingleton==null){ ehSingleton=new LazySingleton();}返回ehSingleton}} instance只有在调用getInstance时才会创建实例,这样做的好处是不占用内存,在单线程模式下比较安全。但是在多线程模式下,if (ehSingleton==null)同时被多个线程执行,结果都为真,就会创建多个实例。因此,上面的懒惰单例是一个带有不安全线程的实例。

  是否多线程安全:是的。

  是否懒加载:是的。

  为了解决多个线程同时执行if (ehSingleton==null)的问题,getInstance方法增加了一个同步锁,保证一个线程进入getInstance方法,其他线程不能进入该方法。只有在执行完成后,其他线程才能进入该方法,同时只能有一个线程进入该方法。

  public类LazySingletonSync { private static LazySingletonSync LazySingletonSync;private LazySingletonSync(){ } public static synced LazySingletonSync getInstance(){ if(LazySingletonSync==null){ LazySingletonSync=new LazySingletonSync();}返回lazySingletonSync}}这种配置虽然保证了线程的安全性,但是效率很低。只有在第一次调用初始化后,才需要同步,初始化后不需要同步。锁的粒度过大,影响程序的执行效率。

  是否多线程安全:是的。

  是否懒加载:是的。

  使用同步声明的方法,当多个线程访问时,例如线程A,其他线程必须等待线程A完成执行才能访问,这是很大的

  降低的程序的运行效率。这个时候使用synchronized代码块优化执行时间,减少锁的粒度

  双重检验首先判断实例是否为空,然后使用synchronized (LazySingletonDoubleCheck.class)使用类锁,锁住整个类,执行完代码块的代码之后,新建了实例,其他代码都不走if (lazySingletonDoubleCheck == null)里面,只会在最开始的时候效率变慢。而synchronized里面还需要判断是因为可能同时有多个线程都执行到synchronized (LazySingletonDoubleCheck.class),如果有一个线程线程新建实例,其他线程就能获取到lazySingletonDoubleCheck不为空,就不会再创建实例了。

  

public class LazySingletonDoubleCheck { private static LazySingletonDoubleCheck lazySingletonDoubleCheck; private LazySingletonDoubleCheck() {} public static LazySingletonDoubleCheck getInstance() { if (lazySingletonDoubleCheck == null) { synchronized (LazySingletonDoubleCheck.class) { if (lazySingletonDoubleCheck == null) { lazySingletonDoubleCheck = new LazySingletonDoubleCheck(); } } } return lazySingletonDoubleCheck; }}

  

静态内部类

是否多线程安全:是

  是否懒加载:是

  外部类加载时,并不会加载内部类,也就不会执行new SingletonHolder(),这属于懒加载。只有第一次调用getInstance()方法时才会加载SingletonHolder类。而静态内部类是线程安全的。

  

  

静态内部类为什么是线程安全

静态内部类利用了类加载机制的初始化阶段方法,静态内部类的静态变量赋值操作,实际就是一个方法,当执行getInstance()方法时,虚拟机才会加载SingletonHolder静态内部类,

  然后在加载静态内部类,该内部类有静态变量,JVM会改内部生成方法,然后在初始化执行方法 —— 即执行静态变量的赋值动作。

  虚拟机会保证方法在多线程环境下使用加锁同步,只会执行一次方法。

  这种方式不仅实现延迟加载,也保障线程安全。

  

public class StaticClass { private StaticClass() {} private static class SingletonHolder { private static final SingletonHolder INSTANCE = new SingletonHolder(); } public static final SingletonHolder getInstance() { return SingletonHolder.INSTANCE; }}

  

总结

饿汉单例类加载就初始化,在没有加锁的情况下实现了线程安全,执行效率高。但是无论有没有调用实例都会被创建,比较浪费内存。为了解决内存的浪费,使用了懒汉单例,但是懒汉单例在多线程下会引发线程不安全的问题。不安全的懒汉单例,使用synchronized声明同步方法,获取实例就是安全了。synchronized声明方法每次线程调用方法,其它线程只能等待,降低了程序的运行效率。为了减少锁的粒度,使用synchronized代码块,因为只有少量的线程获取实例,实例是null,创建实例之后,后续的线程都能获取到线程,也就无需使用锁了。可能多个线程执行到synchronized,所以同步代码块还需要再次判断一次。静态内部类赋值实际是调用方法,而虚拟机保证方法使用锁,保证线程安全。到此这篇关于Java单例模式的五种实现方式的文章就介绍到这了,更多相关Java单例模式内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: