跟着老侯玩编程 跟着老侯玩编程
首页
  • 基础语法
  • 设计模式
  • 基础语法
  • 课程目录
  • 码农宝典
网盘 (opens new window)
留言
首页
  • 基础语法
  • 设计模式
  • 基础语法
  • 课程目录
  • 码农宝典
网盘 (opens new window)
留言
  • 基础语法

    • 单元文件
    • 变量和常量
    • 内联变量
    • 基本数据类型
    • 复合数据类型
    • 语句(选择语句)
    • 语句(循环语句)
    • 数组
    • 初识例程
    • 初识面向对象
    • 属性Property
    • 面向对象的方法
    • 指针
    • 接口
    • 匿名函数和委托实现
    • 多态
    • 字符串详解
    • 异常处理
    • 反射机制
    • 泛型容器
    • JSON
    • 文件操作
    • Dll创建并调用
    • DLL初始化和退出处理
    • Package
    • 理解消息循环
    • VCL与Windows消息
    • 钩子原理
    • 进程通讯-内存映像
    • 多线程开篇
    • 线程控制
    • 线程同步
  • 设计模式

    • 单例模式
    • 单例模式二
      • 同步锁
      • 内部类
    • 策略模式
    • 简单工厂模式
    • 建造者模式
    • 原型模式
    • 模板方法模式
    • 状态模式
    • 迭代器模式
    • 解释器模式
    • 责任链模式
    • 中介者模式
    • 备忘录模式
    • 命令模式
    • 观察者模式
    • 访问者模式
    • 适配器模式
    • 桥接模式
  • Delphi
  • 设计模式
舞动的代码
2022-04-29

单例模式二

​接上篇,细心的朋友可能发现我在上一篇文章中重写类NewInstance和FreeInstance函数,原因是:【在delphi中编译器对构造函数的保护级别进行了处理,即便设为private,编译器仍然会将其修正为public,所以覆盖基类中的NewInstance类方法,系统在每次构造对象时都会调用这个类方法,通过重载它就可以实现对构造函数的控制】,同时在上篇文章中有一段核心代码

我以注释的形式标注这里在并发环境下存在安全隐患,那么现在我们就通过多线程的方式研究一下这个问题?具体做法就是我创建10个线程,反复的调用这个函数

# 调整代码

因为现在的CPU执行速度很快,而我们的代码又不是什么复杂的运算,所以通过添加延时的方式模拟

# 测试代码

# 执行结果

结论:我们发现当以多线程的方式访问时出现了创建多个TSingle类对象的情况,这就是我前面提的并发环境下的安全问题

# 原因分析

# 解决方案

解决方案主要有两种

  • 通过同步锁(线程锁)的方式解决,但是这种方式会存在效率的问题,我们知道一旦代码需要同步的时其实就是以单线程的方式在执行

  • 通过内部类的方式解决,这种方式解释起来比较费劲,我也没有深究过Delphi类的加载机制

# 同步锁

临界区对象初始化和销毁

class function TSingle.GetInstance: TSingle;
begin
    //临界区开始
    CriticalSection.Enter;
    if GlobalSingle = nil then begin
        //添加延迟模拟多线程暂留
        TThread.Sleep(1000);
        GlobalSingle := TSingle.create();
    end;
​
    //临界区结束
    CriticalSection.Leave;
​
    Result := GlobalSingle;
end;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

测试的代码不变,我们会发现问题已经成功的被解决了

# 内部类

完整的代码如下:

uCommonUtil单元

unit uCommonUtil;
​
interface
​
uses
    system.SyncObjs, System.Classes, System.SysUtils;
​
type
    TStringBuild = class(TObject)
    private
        constructor Create;
    public
        //其实这个地方可以设置为private的然后提供一个public的函数,偷个懒
        type
            Build = class
                //注意函数的返回值
                class function GetInstance(): TStringBuild;
            end;
        class function NewInstance: TObject; override;
        procedure FreeInstance; override;
    end;
​
implementation
​
var
​
    { TStringBuild }
    StringBuild: TStringBuild = nil;
​
constructor TStringBuild.Create;
begin
    Writeln('TStringBuild的构造方法');
end;
​
procedure TStringBuild.FreeInstance;
begin
    inherited;
    StringBuild := nil;
end;
​
class function TStringBuild.NewInstance: TObject;
begin
    if StringBuild = nil then
        //重载方法通过父类  NewInstance方法获取对象,强制转换为 TSingle类型
        StringBuild := TStringBuild(inherited NewInstance);
    Result := StringBuild;
end;
​
//内部类的类方法
class function TStringBuild.Build.GetInstance: TStringBuild;
begin
    if StringBuild = nil then
        StringBuild := TStringBuild.create();
    Result := StringBuild;
end;
​
initialization
​
finalization
​
end.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

测试单元


​program ProjectSingle;
​
{$APPTYPE CONSOLE}
{$R *.res}
​
uses
    System.Classes,
    System.SysUtils,
    System.Types,
    uCommonUtil in 'uCommonUtil.pas';
​
procedure Demo2();
begin
    try
​
        for var I := 1 to 100 do begin
            TThread.CreateAnonymousThread(
                procedure
                begin
                    var instance := TStringBuild.Build.GetInstance();
​
                    writeln(IntToStr(TThread.CurrentThread.ThreadID) + ':' + IntToStr(Integer(instance)));
                end).Start;
        end;
​
    except
        on e: Exception do
            writeln(e.Message);
    end;
​
    readln;
end;
​
begin
    Demo2();
end.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

执行结果

以内部类的方式来解决貌似是我现在能够想到最靠谱的解决方案了,各位有什么好的方法可以给我留言

上次更新: 2022/05/05, 14:24:28
单例模式
策略模式

← 单例模式 策略模式→

Theme by Vdoing | Copyright © 2013-2022 冀ICP备16006233号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×