• Java设计模式—Singleton


    单例模式的特点:

      1、单例模式只能有一个实例

      2、单利类必须自己创建自己的唯一实例

      3、单例类必须给所有的其他对象提供这一实例

      概述:保证一个类,只有一个实例存在,同时提供对该实例加以访问的全局访问方法。

    单例模式的运用:线程池,缓存,日志对象,对话框,打印机,显卡驱动常常被设计为单例模式。主要就是避免不一致状态。

    单例模式的实现方式:

      懒汉式

      饿汉式

      双重检查

    一、懒汉式

     1 package cn.zpoor.singletonBlog;
     2 //懒汉式单例模式,在第一次调用的时候实例化自己
     3 public class Singleton {
     4     private static Singleton singleton = null;
     5     private Singleton() {}
     6     
     7     //实现全局方法(静态工厂方法)
     8     public static Singleton getSingleton() {
     9         if (singleton == null) {
    10             singleton = new Singleton();
    11         }
    12         return singleton;
    13     }
    14 }

    解释:

      私有化的构造方法,避免在外部类实例化,Singleton的唯一实例只能通过getSingleton()方法访问。

      但是懒汉式单例没有考虑线程的安全,多线程环境下可能会出现多个Singleton实例,实现线程安全有多种方法。举个栗子

    1、在getSingleto()方法加上同步锁

    1 public static synchronized Singleton getSingleton() {
    2         if (singleton == null) {
    3             singleton = new Singleton();
    4         }
    5         return singleton;
    6     }

    2、双重检查

     1 public static Singleton getSingleton() {
     2         if (singleton == null) {
     3             synchronized (Singleton.class) {
     4                 if (singleton == null) {
     5                     singleton = new Singleton();
     6                 }
     7             }
     8         }
     9         return singleton;
    10     }

    3、静态内部类(实现了线程安全,又避免同步带来的性能影响)

     1 public class Singleton {
     2     public static class Lazy {
     3         private static final Singleton INSTANCE = new Singleton();
     4     }
     5     
     6     private Singleton() {
     7         
     8     }
     9     
    10     public static final Singleton getSingleton() {
    11         return Lazy.INSTANCE;
    12     }
    13 }

    二、饿汉式

     1 package cn.zpoor.singletonBlog;
     2 //饿汉式单例,在类初始化时,已经自行初始化
     3 public class Singleton {
     4     private static final Singleton SINGLETON = new Singleton();
     5     
     6     private Singleton() {
     7         
     8     } 
     9     
    10     //静态全局方法
    11     public static Singleton getSingleton () {
    12         return SINGLETON;
    13     }
    14 }

    在类创建的时候就已经创建好一个静态的对象提供给系统使用,不在改变,所以线程是安全的。

    懒汉和饿汉的区别:

      字面上一个懒一个饿。

      饿汉:类一旦初始化,单例初始化完成,调用getSingleton的时候,单例已经存在

      懒汉:只有在调用getSingleton的时候,才会去初始化这个单例

    从线程安全上面:

      饿汉式天生就是安全的,可以直接用于多线程,不会出现问题

      懒汉式本身是非线程安全的,实现线程安全一般是加同步锁、双重检查,静态内部类

    从资源加载和性能上面:

      饿汉式在类创建的时候就会实例化一个静态的对象,不管以后用不用,都会占据内存,相应的在第一次调用的速度会很快,已经初始化完成了。

      懒汉式会延迟加载,第一次使用该单例的时候才会实例化该对象出来,第一次调用会初始化,速度上比较慢一点。

        1、同步锁

          在方法上调用上加上同步锁,线程安全了,但是每次都要同步,会影响性能

        2、双重检查

          在getSingleton中做了两次null检查,确保了只有第一次调用该单例的时候才会做同步,这样也是线程安全的,同时避免了每次同步的性能损耗。

        3、静态内部类

          利用了classloader的机制来保证初始化INSTANCE时只有一个线程,所以线程也是安全的,同时没有性能的损耗。(推荐)

    什么是线程安全:

      代码在所在的进程中有多个线程在同时运行,这些线程可能会同时运行这些代码。如果每次运行的结果和单线程运行的结果一致,其他变量的值也是和预期一致,这样就是线程安全的。

      一个类或者程序提供的接口对于线程来说是源自操作,或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是不用考虑同步问题,这也是线程安全的

    单例模式的应用:

      饿汉式,使用双重检查

     1 package cn.zpoor.singletonBlog;
     2 public class Singleton {
     3     private String name;
     4     private static volatile Singleton instance = null;
     5 
     6     public String getName() {
     7         return name;
     8     }
     9 
    10     public void setName(String name) {
    11         this.name = name;
    12     }
    13     
    14     private Singleton() {}
    15     
    16     public static Singleton getInstance() {
    17         if (instance == null) {
    18             synchronized (Singleton.class) {
    19                 if (instance == null) {
    20                     instance = new Singleton();
    21                 }
    22             }
    23         }
    24         return instance;
    25     }
    26     
    27     public void info() {
    28         System.out.println("name is" + name);
    29     }
    30 }

    测试代码:

      

     1 package cn.zpoor.singletonBlog;
     2 
     3 public class TestSingleton {
     4     public static void main(String[] args) {
     5         Singleton s1 = Singleton.getInstance();
     6         Singleton s2 = Singleton.getInstance();
     7         
     8         s1.setName("WY");
     9         s2.setName("Zpoor");
    10         
    11         s1.info();
    12         s2.info();
    13         
    14         if (s1 == s2) {
    15             System.out.println("这是单例模式");
    16         } else {
    17             System.out.println("这是多例模式");
    18         }
    19     }
    20 }
    21 
    22 
    23 /*结果:
    24       
    25     name isZpoor
    26     name isZpoor
    27     这是单例模式
    28  */

    总结:

      一个类只有一个实例,还要提供全部访问的方法,注意懒汉饿汉的区别,线程安全等等。

  • 相关阅读:
    如何复用网页
    sap
    学习方法
    spring + ehcache 实例
    200个 jquery插件
    vs 示例代码浏览器 搜索
    struts jquery 整合
    eclipse clean 后clease 为空
    mvc相关
    css 框架
  • 原文地址:https://www.cnblogs.com/zpoor/p/7881953.html
Copyright © 2020-2023  润新知