c语言中如何确保一个程序是单例的_设计模式——单例模式(1-2点)

单例模式

Singleton Pattern

  1. 单例模式概述
  2. 单例模式的结构与实现
  3. 单例模式的应用实例
  4. 饿汉式单例与懒汉式单例
  5. 单例模式的优缺点与适用环境
  6. 多例模式Multiton
  7. 反射对单例模式破坏和枚举类型enum()

1.单例模式概述

Windows任务管理器

像Logger、SystemInfo、PrintServer、java的RunTime等

这些类在整个系统中只应存在一个实例。

0003c8ab9034ee542b624ee26253f78f.png

如何保证一个类只有一个实例并且这个实例易于被访问?

(1) 全局变量:可以确保对象随时都可以被访问,但不能防止创建多个对象

(2) 让类自身负责创建和保存它的唯一实例,并保证不能创建其他实例,它还提供一个访问该实例的方法

  • 单例模式的定义
单例模式:确保一个类 只有一个实例,并提供一个 全局访问点来访问这个唯一实例。 Singleton Pattern: Ensure a class has only one instance, and provide a global point of access to it.

要点:

  • 某个类只能有一个实例
  • 必须自行创建这个实例
  • 必须自行向整个系统提供这个实例

单例模式的结构与实现

  • 单例模式的结构
8559965896a0728daaf8a556b9350a4b.png

定义单例类MyClass

1. 使MyClass类的构造方法私有

private MyClass(){ //constructor code}

2.定义一个私有的、静态的、(不变的)MyClass类成员变量,类型是MyClass

private static (final) Myclass singletonOfMyClass

3. 定义一个访问成员变量的静态方法

public static MyClass getSingletonOfMyclass(){ return singletonOfMyClass ; }

Cannot make a static reference to the non-static field.

饿汉模式和懒汉模式

86b2c63bf3299f7f20c30b21c94fa832.png

饿汉模式:当类被加载时,静态变量(singletonOfMyClass)会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将被创建。

懒汉模式:与饿汉模式不同,懒汉模式在第一次被引用时将自己实例化,在懒汉模式单例类被加载时不会将自己实例化。(延迟加载技术,避免多线程同时调用getSingletonOfMyClass,加上synchronized)

0febeca7f32ce1d19e080c9c2aa47b22.png

编发编程:原子性、可见性、有序性

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。

2)禁止进行指令重排序。

《深入理解Java虚拟机》:

程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;

锁定规则:一个 unLock 操作先行发生于后面对同一个锁的 lock 操作;

volatile 变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;

传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;

线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;

线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;

线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;

对象终结规则:一个对象的初始化完成先行发生于他的 finalize() 方法的开始;

对象在初始化的时候分三个步骤:

memory = allocate(); //1. 分配对象的内存空间

ctorInstance(memory); //2. 初始化对象

instance = memory; //3. 设置 instance 指向对象的内存空间

因为步骤 2 和步骤 3 需要依赖步骤 1,而步骤 2 和 步骤 3 并没有依赖关系,所以这两条语句有可能会发生指令重排,也就是或有可能步骤 3 在步骤 2 的之前执行。在这种情况下,步骤 3 执行了,但是步骤 2 还没有执行,也就是说 instance 实例还没有初始化完毕,正好,在此刻,线程 2 判断 instance 不为 null,所以就直接返回了 instance 实例,但是,这个时候 instance 其实是一个不完全的对象,所以,在使用的时候就会出现问题。

饿汉模式与懒汉模式比较:

饿汉式单例类在类被加载时就将自已实例化,它的优点在于无须考虑多个线程同时访问的问题,可以确保实例的唯一性; 从调用速度和反应时间角度来讲,由于单例对象一开始就得以创建,因此要优于懒汉式单例。但是无论系统在运行时是否需要使用该单例对象,由于在类加载时该对象就需要创建,因此从资源利用效率角度来讲饿汉式单例不及懒汉式单例,而且在系统加载时由于需要创建饿汉式单例对象,加载时间可能会比较长。

懒汉式单例类在第一次使用时创建,无须一直占用系统资源,实现了延迟加载,但是必须处理多个线程同时访问的问题,特别是当单例类作为资源控制器,在实例化时必然涉及费源初始化,而资源初始化很有可能耗费大量时间,这意味着出现多线程同时首次引用此类的几率变得较大,需要通过双重检查锁定等机制进行控制,这将导致系统性能受到定影响。

解决方法

使用静态内部类实现单例模式(需要语言支持)

Java可以通过Initialization on Demand Holder (IoDH)

public class Singleton {private Singleton(){};//静态内部类private static class HolderClass{private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance(){return HolderClass.INSTANCE;}public static void main(String[] args){Singleton s1,s2;s1=Singleton.getInstance();s2=Singleton.getInstance();System.out.println(s1==s2);}}

不同语言在实现单例模式虽然有区别,但是单例模式的意图是一致的

确保对象唯一!

b62814e4382e3df285e02f67b63e8f1c.png

未完待续.......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值