单例设计模式

Posted tkzl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例设计模式相关的知识,希望对你有一定的参考价值。

前言快速到底

  本文的关注点将重点放在单例模式的写法以及每种写法的线程安全性上。所谓 "线程安全" 的意思就是保证在创建单例对象的时候不存在竞争,只会创建出一个单例对象。

 

单例模式

 

  作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类。单例模式有以下特点:

 

  1、单例类只能有一个实例

 

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

 

  3、单例类必须给其他所有需要它的地方提供这一实例

 

下面看一下单例模式的几种写法

一、饿汉式

package com.singleton;

public class Singleton
{
    private static final Singleton singleton = new Singleton(); // 饿汉式
    
    public static Singleton getInstance()
    {
        return singleton;
    }
    
}

饿汉式是不存在线程安全问题的,因为类一加载就会创建这个对象,关于这部分可以参考这篇博客

 二、懒汉式

 1 public class Singleton
 2 {
 3     private static Singleton instance = null; // 懒汉式
 4 
 5     public static Singleton getInstance()
 6     {
 7         if (instance == null)
 8         {
 9             instance = new Singleton();
10             return instance;
11         }
12 
13         return null;
14     }
15 
16 }

懒汉式最开始就是上面的这种写法,但是你会发现如果有两个线程同时走到第 7 行,然后判断都为空,然后这两个线程就都会走第 9 行进行创建对象,那么实际上就会创建出两个对象。那么改进之后的第一版

 1 public class Singleton
 2 {
 3     private static Singleton instance = null; // 懒汉式
 4 
 5     public static Singleton getInstance()
 6     {
 7         synchronized (Singleton.class)
 8         {
 9             if (instance == null)
10             {
11                 instance = new Singleton();
12                 return instance;
13             }
14         }
15 
16         return null;
17     }
18 
19 }

根据上面的缺点在第 7 行加了一个同步方法,也就是说每次进行判断 instance 为不为 null 和 创建对象的这两个操作都只能有一个线程进来,这样就保证了线程安全。但是这个写法有一个问题,你会发现无论 instance 为不为 null,两个线程都会执行第 7 行的内容,很显然,如果 instance 都已经存在了,那同步方法中的内容都不要执行了,毕竟多线程执行同步方法中的内容还是很消耗效率的。

采用双重校验锁的方式来优化上面的缺点

 1 public class Singleton
 2 {
 3     private static Singleton instance = null; // 懒汉式
 4 
 5     public static Singleton getInstance()
 6     {
 7         if(instance == null)
 8         {
 9             synchronized (Singleton.class)
10             {
11                 if (instance == null)
12                 {
13                     instance = new Singleton();
14                     return instance;
15                 }
16             }
17         }
18 
19         return null;
20     }
21 
22 }

三、静态内部类

public class Singleton
{
    
    static class InnerClass      
    {
        private static Singleton INSTANCE = new Singleton();  
    }
    
    public static Singleton getInstance()
    {
        return InnerClass.INSTANCE;
    }
    
}

关于静态内部类的方式实现单例设计模式在内部类的加载时机以及静态内部类和普通内部类的一些问题上有疑问,解答见这篇博客

 

以上是关于单例设计模式的主要内容,如果未能解决你的问题,请参考以下文章

常用代码片段

性能比较好的单例写法

片段作为 Android 中的单例

单例片段或保存网页视图状态

从 Viewpager2 片段访问父片段函数

你熟悉的设计模式都有哪些?写出单例模式的实现代码