[设计模式]单例模式

简介

单例模式(Singleton Pattern)保证一个类只有一个实例,并提供一个访问它的全局访问点

单例模式是一种对象创建型模式可参考 设计模式 创建型模式)。

单例模式是设计模式中最简单的模式。它的用途就是使得类的一个对象成为系统中的唯一实例

结构

图-单例模式结构图

Singleton : 定义一个接口 Instance() 使得客户端可以访问它的唯一实例。

动机

在以下情况中,可以考虑应用单例模式:

  • 保证一个类只有一个实例,并提供一个访问它的全局访问点。
  • 当唯一的实例应该对子类可扩展,并且用户应该可以在不改变代码的情况下使用扩展的实例。

实际应用场景

一些资源管理器常常设计成单例模式。

在计算机系统中,需要管理的资源包括软件外部资源,譬如每台计算机可以有若干个打印机,但只能有一个Printer Spooler, 以避免两个打印作业同时输出到打印机中。

每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。任务管理器中难以启动两个相同的task。

要点

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

需要定义一个该类的静态私有变量,使这个类的所有对象都共用这个实例。 

2、实例必须由类自行创建。

单例模式的类只能提供私有的构造函数。如此,才能保证外部无法实例化这个类的对象。

3、必须提供获取实例的方法。

单例模式的类必须提供一个公共的静态函数用于创建或获取它本身的静态私有对象

实例

1、懒汉式

你不找懒汉,懒汉根本就懒得去初始化自己的实例。 

instance 初始时没有初始化,只有当第一次调 getInstance() 时才创建实例。

缺点:当有两个线程调 getInstance() 方法,当它们同时执行到 if (null == instance) 这行代码,instancenull

继续向下执行,会生成两个实例,违背了单例模式的初衷。 

 public class LazySingleton {
 private LazySingleton() {
         System.out.println("Singleton()");
     }
 
 private static LazySingleton instance = null;
 
 public static LazySingleton getInstance() {
 if (null == instance) {
             instance = new LazySingleton();
         }        
 return instance;
     }
 } 

2、饿汉式

饿汉根本等不及别人来找他,不管三七二十一先初始化了自身的实例,生怕自己饿着了。

类默认先直接初始化一个实例,以后调用 getInstance() 总是返回这个已创建好的实例。

缺点:在没有必要获取实例时,已经预先产生了开销。

优点:规避了懒汉式方法的线程问题,不用显示编写线程安全代码。

 public class HungerSinleton {
 private HungerSinleton() {
         System.out.println("Singleton()");
     }
 
 private static HungerSinleton instance = new HungerSinleton();
 
 public static HungerSinleton getInstance() {
 return instance;
     }
 } 

3、双重锁的形式

如果既不想在没有调用 getInstance() 方法时产生开销,又不想发生线程安全问题,就可以采用双重锁的形式。

 public class SyncSingleton {
 private SyncSingleton() {
         System.out.println("Singleton()");
     }
 
 private static SyncSingleton instance = null;
 
 public static SyncSingleton getInstance() {
 if (null == instance) {
 synchronized(SyncSingleton.class) {
 if (null == instance) {
                     instance = new SyncSingleton();
                 }
             }
         }
 return instance;
     }
 } 

注:在外面判断了instance实例是否存在,为什么在锁定后又要在内部又判断一次?

这是因为,如果 instance null 时有两个线程同时调用 getInstance(),由于 synchronized 机制,只有一个线程可以进入,另一个需要等待。

这时如果没有第二道 instance 是否为 null 的判断,就可能发生第一个线程创建一个实例,而第二个线程又创建一个实例的情况。

C++版单例模式

下面是一个采用饿汉式的例子

#include "stdafx.h"
#include <iostream>
using namespace std;

class Singleton
{
private:
 static Singleton *m_instance;
    Singleton()
    {
        cout << "Singleton Construct" << endl;
    }
public:
 static Singleton* GetInstance()
    {
 return m_instance;
    }
};

Singleton* Singleton::m_instance = new Singleton();


int main()
{
 //Singleton *pSingletonA = new Singleton;  //编译会报错,因为不能访问私有函数
    Singleton *pSingletonA = Singleton::GetInstance();
    Singleton *pSingletonB = Singleton::GetInstance();

 if (pSingletonA == pSingletonB)
        cout << "Same Instance" << endl;
 return 0;
}

推荐阅读

本文属于 设计模式系列

参考资料

《大话设计模式》

《HeadFirst设计模式》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java架构沉思录

聊聊设计模式之单例模式(上)

前言 单例模式应该是设计模式中最容易理解也是用得最多的一种模式了,同时也是面试的时候最常被问到的模式。单例模式的作用就是确保在任何情况下都只有一个实例对象,并提...

3346
来自专栏小樱的经验随笔

【Java学习笔记之三十】详解Java单例(Singleton)模式

概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例、饿汉式单例、登记式单例。   单例模式有以下特点: 1...

2565
来自专栏好好学java的技术栈

java设计模式系列:单例模式

  1、单例类只能有一个实例。   2、单例类必须自己创建自己的唯一实例。   3、单例类必须给所有其他对象提供这一实例。

753
来自专栏yukong的小专栏

设计模式之单例模式讲解设计模式之单例模式讲解

Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点

673
来自专栏飞雪无情的博客

Go语言实战笔记(七)| Go 类型

Go 语言是一种静态类型的编程语言,所以在编译器进行编译的时候,就要知道每个值的类型,这样编译器就知道要为这个值分配多少内存,并且知道这段分配的内存表示什么。

543
来自专栏xingoo, 一个梦想做发明家的程序员

Java几种单例模式的实现与利弊

多线程环境下无法保证单例效果,会多次执行 instance=new Singleton(),需要考虑到多线程

1292
来自专栏编程之路

羊皮书APP(Android版)开发系列(二十二)10分钟秒懂单例模式

713
来自专栏用户画像

JAVA单例模式

在整个应用中,保证一个类只有一个实例,它提供了一个可以访问到它自己的全局访问点(静态方法)。

642
来自专栏机器学习从入门到成神

Spring在 IOC 容器中 Bean 之间的关系

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/articl...

731
来自专栏Java技术分享

反射类的main方法

有时候我们需要调用一个类的Main方法,也可说是执行这个类的代码。但是这时候这个类我们还没有写好,或者这个类是通过网络运行时传给我们的,我们就不可能在程序中知道...

1796

扫码关注云+社区