当前位置: 首页 > news >正文

一、单例模式

单例模式(Singleton Pattern)是一种常用的设计模式,确保一个类只有一个实例,并提供一个全局访问点。它通常用于节省系统资源或实现共享的资源,比如配置文件、数据库连接等。单例模式可以通过多种方法实现,通常有以下几种主要形式:

1. 饿汉式单例

在这种实现中,单例实例在类加载时就创建好,无需等到使用时再创建。因为实例在类加载时创建,所以线程安全,且不允许有延迟初始化。

java

public class Singleton {//1、创建私有对象private static final Singleton singleton = new Singleton();//2、创建私有构造函数private Singleton(){}//3、提供对外获取对象的公共方法public static Singleton getInstance(){return singleton;}
}
@Test(description = "多线程验证饿汉式-单例", threadPoolSize = 2, invocationCount = 10)public void singletonTest(){Singleton instance = Singleton.getInstance();System.out.println("Hash Code: " + instance.hashCode());}

go

// Singleton 定义一个结构体(类)
type Singleton struct {name string
}
// 声明一个结构体实例(对象)
var singleton *Singleton// 定义init函数构造结构体实例(对象)
func init() {fmt.Println("Singleton initialized")singleton = &Singleton{name: "饿汉式单例"}
}
// GetSingLeton 提供一个外获取Singleton对象的函数
func GetSingLeton() *Singleton {return singleton
}
// TestGetInstance 多线程验证饿汉-单例
func TestGetInstance(t *testing.T) {//声明一个计数器var wg sync.WaitGroupfor i := 0; i < 10; i++ {wg.Add(1)go func(i int) {defer wg.Done()leton := GetSingLeton()fmt.Printf("inst1: %p\n", leton)}(i)}wg.Wait()fmt.Println("All workers done")
}

2. 懒汉式单例

java 为了确保线程安全,可以在 getInstance 方法中使用 synchronized 关键字。然而,这会导致性能下降,因为每次调用都必须进行同步。

public class SingletonLazy {//1、创建私有对象private static SingletonLazy singletonLazy ;//2、创建私有构造函数private SingletonLazy(){}//3、提供对外获取对象的公共方法public static synchronized SingletonLazy getInstance(){if (singletonLazy == null) {singletonLazy = new SingletonLazy();}return singletonLazy;}
}
@Test(description = "多线程验证懒汉式-单例", threadPoolSize = 2, invocationCount = 10)public void singletonLazyTest(){SingletonLazy instance = SingletonLazy.getInstance();System.out.println("Hash Code: " + instance.hashCode());}

go sync.Once 确保初始化逻辑只执行一次。是线程安全的

// SingletonLazy 定义一个结构体(类)
type SingletonLazy struct {name string
}// 声明对象
var (lazySingleton *SingletonLazyonce          sync.Once
)func GetLazySingleton() *SingletonLazy {// sync.Once 确保初始化逻辑只执行一次。once.Do(func() {fmt.Println("只执行一次")lazySingleton = &SingletonLazy{name: "懒汉式-单例"}})return lazySingleton
}
// TestGetLazySingleton 多线程下验证懒汉式-单例
func TestGetLazySingleton(t *testing.T) {// 声明一个计算期var wg sync.WaitGroupfor i := 0; i < 10; i++ {wg.Add(1)go func(i int) {defer wg.Done()getLazySingleton := GetLazySingleton()fmt.Printf("inst1: %p\n", getLazySingleton)}(i)}wg.Wait()fmt.Println("All workers done")
}

3. 双重检查锁定

java

通过双重检查锁定来实现线程安全的懒汉式单例模式,减少了对性能的影响。

synchronized

  • synchronized 是 Java 提供的关键字,用于同步代码块。
  • 它确保同时只能有一个线程执行被同步的代码块,这样可以防止多个线程同时访问这段代码并创建多个实例。

(DoubleCheckedSingleton.class)

  • DoubleCheckedSingleton.class 表示对该类的类对象进行同步。
  • 这意味着任何线程在进入这个代码块之前必须获得 DoubleCheckedLockingSingleton 类的锁。
  • 通过在类级别上同步,不同的实例之间不会相互干扰。

工作机制

当第一次调用 getInstance() 方法时,代码会进行如下操作:

  1. 第一次检查:在进入同步代码块之前,检查 instance 是否为 null。如果不是 null,则返回已有实例。此检查是为了在实例已经存在时避免不必要的加锁,提升性能。

  2. 同步块:如果 instancenull,进入同步代码块,并对类进行加锁。此时,只有获取了该锁的线程才能继续执行。

  3. 第二次检查:在同步块内,重新检查 instance 是否为 null。这是因为在不同线程之间,可能有线程在第一个检查后已经创建了实例。

  4. 实例化:如果依然为 null,则创建一个新的实例并赋值给 instance

总结

通过这种方式,只有在 instancenull 的情况下,才会使用同步机制,加锁几乎所有线程,以确保只有一个线程创建实例。这种“双重检查”模式在确保线程安全的同时,最大程度地减少性能开销。这样,你可以在多线程环境中安全地获取单例实例。

private static volatile DoubleCheckSingleton instance;private DoubleCheckSingleton() {// 私有构造函数}public static DoubleCheckSingleton getInstance() {if (instance == null) {synchronized (DoubleCheckSingleton.class) {if (instance == null) {instance = new DoubleCheckSingleton();}}}return instance;}
@Test(description = "多线程验证双重检查式-单例", threadPoolSize = 2, invocationCount = 10)public void doubleCheckSingletonTest(){DoubleCheckSingleton instance = DoubleCheckSingleton.getInstance();System.out.println("Hash Code: " + instance.hashCode());}

go

sync.Once 本质就是双重校验的实现,下面是源码

func (o *Once) Do(f func()) {//判断是否执行过该方法,如果执行过则不执行if atomic.LoadUint32(&o.done) == 1 {return}// Slow-path.o.m.Lock()defer o.m.Unlock()//进行加锁,再做一次判断,如果没有执行,则进行标志已经扫行并调用该方法if o.done == 0 {defer atomic.StoreUint32(&o.done, 1)f()}
}

当然也可以自己实现

/锁对象
var lock sync.Mutex//第一次判断不加锁,第二次加锁保证线程安全,一旦对象建立后,获取对象就不用加锁了。
func GetInstance() *Tool {if instance == nil {lock.Lock()if instance == nil {instance = new(Tool)}lock.Unlock()}return instance
}

http://www.mrgr.cn/news/12812.html

相关文章:

  • 第一周学习--联邦学习
  • 4 Python虚拟环境【详细解释】但【超级简单易懂!!!】
  • mysql覆盖索引和超大页解决
  • 网络通信编程UDP/TCP
  • Vue2路由守卫:解决路由传参页面刷新后参数消失的问题
  • IntelliJ IDEA智能代码补全​和集成AI助手说明及操作
  • uniapp video标签无法播放视频
  • C++-标准库 智能指针smart pointer
  • 端口号问题(开发)
  • 云微客短视频矩阵如何打造多元化的视频内容呢?
  • 交换机自动化巡检(H3C)
  • linux下一切皆文件,如何理解?
  • 谁说微生态研究都是结果描述?
  • 【区块链 + 司法存证】枢纽链:区块链司法存证平台 | FISCO BCOS应用案例
  • 怎么把mp4转换成mp3?5种转换方法教会你
  • 【架构设计】安全架构设计
  • 在idea中回滚到某节点并push到远程仓库
  • 系统编程-消息队列
  • 【STM32】FSMC
  • leetcode 560 和为k 的子数组