行业资讯 2025年08月6日
0 收藏 0 点赞 483 浏览 2624 个字
摘要 :

文章目录 1. 线程安全的懒汉式单例 2. 双重检查锁定(DCL) 3. 原子操作法 总结 Go语言如何实现单例模式?有哪几种方法?实现单例模式(Singleton Pattern)的核心使命……




  • 1. 线程安全的懒汉式单例
  • 2. 双重检查锁定(DCL)
  • 3. 原子操作法
  • 总结

Go语言如何实现单例模式?有哪几种方法?实现单例模式(Singleton Pattern)的核心使命是确保一个类仅有一个实例,并为程序提供一个全局访问该实例的入口。在实际场景中,当你需要严格控制某个对象的实例数量为一个时,单例模式就大显身手了,比如数据库连接池、日志管理器、配置管理器等组件的设计,它都能派上用场。

接下来,我们深入Go语言的世界,介绍3种实现单例模式的方式。

1. 线程安全的懒汉式单例

懒汉式单例的设计思路十分巧妙,它不会在程序启动时就迫不及待地创建实例,而是一直推迟到第一次被调用时才进行实例化操作。在多线程环境下,为了保证这种延迟创建的安全性,Go语言标准库中的 sync.Once 发挥了关键作用,它能确保实例仅被创建一次。

package main

import (
    \"fmt\"
    \"sync\"
)

var wg sync.WaitGroup

// Singleton 类型
type Singleton struct {
}

var instance *Singleton
var once sync.Once

// GetInstance 提供全局唯一的实例
func GetInstance() *Singleton {
    once.Do(func() {
        instance = &Singleton{}
    })
    return instance
}

func main() {
    // 获取单例实例
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(index int) {
            defer wg.Done()
            s1 := GetInstance()
            fmt.Printf(\"index %d, memery address: %pn\", index, s1)
        }(i)
    }
    wg.Wait()
}

运行上述代码,你会得到类似这样的结果:

index 0, memery address: 0x56c480
index 5, memery address: 0x56c480
index 4, memery address: 0x56c480
index 2, memery address: 0x56c480
index 7, memery address: 0x56c480
index 9, memery address: 0x56c480
index 6, memery address: 0x56c480
index 8, memery address: 0x56c480
index 3, memery address: 0x56c480
index 1, memery address: 0x56c480

这表明,无论在多少个并发线程中获取实例,得到的都是同一个对象。

这里的 sync.Once 是Go语言并发编程中的一个重要同步原语,它保证了传入的函数只会被执行一次。而 once.Do 方法则是具体执行这个确保唯一性操作的关键,非常适合用于懒加载单例实例的场景。

2. 双重检查锁定(DCL)

双重检查锁定(Double-Checked Locking,简称DCL)是一种优化手段,旨在减少加锁带来的性能开销。它的实现方式是通过两次检查实例是否为空,从而提高获取单例的效率。

package main

import (
    \"fmt\"
    \"sync\"
)

var wg sync.WaitGroup

// Singleton 类型
type Singleton struct {
}

var instance *Singleton
var lock sync.Mutex

func GetInstance() *Singleton {
    if instance == nil {
        lock.Lock()
        defer lock.Unlock()
        if instance == nil {
            instance = &Singleton{}
        }
    }
    return instance
}

func main() {
    // 获取单例实例
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(index int) {
            defer wg.Done()
            s1 := GetInstance()
            fmt.Printf(\"index %d, memery address: %pn\", index, s1)
        }(i)
    }
    wg.Wait()
}

在这个实现中,首先会进行一次快速检查,判断实例是否已经存在。如果实例为空,才会进入加锁流程。加锁后,会再次检查实例是否为空,只有在此时实例仍然为空的情况下,才会创建实例。这种方式避免了每次获取实例时都进行加锁操作,大大提升了性能。

3. 原子操作法

Go语言的 sync/atomic 包提供了强大的原子操作功能,利用这一特性,我们也可以实现线程安全的单例模式。

package main

import (
    \"fmt\"
    \"sync\"
    \"sync/atomic\"
    \"unsafe\"
)

var wg sync.WaitGroup

type Singleton struct {
}

var instance unsafe.Pointer

func GetInstance() *Singleton {
    // 使用原子操作获取实例
    if atomic.LoadPointer(&instance) == nil {
        newInstance := &Singleton{}
        atomic.StorePointer(&instance, unsafe.Pointer(newInstance))
    }
    return (*Singleton)(atomic.LoadPointer(&instance))
}

func main() {
    // 获取单例实例
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(index int) {
            defer wg.Done()
            s1 := GetInstance()
            fmt.Printf(\"index %d, memery address: %pn\", index, s1)
        }(i)
    }
    wg.Wait()
}

在这段代码中,unsafe.Pointer 绕过了Go语言的类型系统,让我们可以直接操作内存地址。而 atomic.LoadPointeratomic.StorePointer 这两个原子操作函数,则确保了对指针的加载和存储操作是线程安全的,从而保证了单例实例赋值的安全性。

总结

在Go语言中,实现单例模式的方法多种多样,上述介绍的使用 sync.Once、双重检查锁定以及原子操作法是比较常见的方式。每种方法都有其独特的优缺点,在实际应用中,我们需要根据具体的业务场景和性能需求,选择最合适的实现方式,在保障线程安全的同时,实现性能的优化。

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/10248.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号