皮皮网

【bsc部署合约源码】【游戏源码带工具】【玄铁910源码】getinstance源码

2024-12-29 06:45:34 来源:盲盒提现源码

1.JAVA实例化问题(Calendar obj=Calendar.getInstance();)
2.Go并发编程 — sync.Once

getinstance源码

JAVA实例化问题(Calendar obj=Calendar.getInstance();)

       就拿Calender类来说,他本身是个抽象类,有部分方法需要是bsc部署合约源码抽象的,所以本身不能通过new的方法来实例化,需要借助于一些已经把抽象方法实现的游戏源码带工具子类来实例化,实例化方法都写在getInstance()方法里,玄铁910源码你可以参考以下源代码。

       他这么设计实际上是非常巧妙的,当对抽象方法的普遍实现(使用getInstance()来实例化)不能满足你的需求的时候,你就应该自己来实现它。比如:

       public class CalenderEx extends Calender {

       }

       Calender cal = new CalenderEx();

Go并发编程 — sync.Once

       ç®€ä»‹

       Once 可以用来执行某个函数,但是这个函数仅仅只会执行一次,常常用于单例对象的初始化场景。说到这,就不得不说一下单例模式了。

单例模式

       å•ä¾‹æ¨¡å¼æœ‰æ‡’汉式和饿汉式两种,上代码。

饿汉式

       é¥¿æ±‰å¼é¡¾åæ€ä¹‰å°±æ˜¯æ¯”较饥饿,所以就是上来就初始化。

var?instance?=?&Singleton{ }type?Singleton?struct?{ }func?GetInstance()?*Singleton?{ return?instance}懒汉式

       æ‡’汉式顾名思义就是偷懒,在获取实例的时候在进行初始化,但是懒汉式会有并发问题。并发问题主要发生在 instance == nil 这个判断条件上,有可能多个 goruntine 同时获取 instance 对象都是 nil ,然后都开始创建了 Singleton 实例,就不满足单例模式了。

var?instance?*Singletontype?Singleton?struct?{ }func?GetInstance()?*Singleton?{ if?instance?==?nil?{ ?instance?=?&Singleton{ }}return?instance}加锁

       æˆ‘们都知道并发问题出现后,可以通过加锁来进行解决,可以使用 sync.Metux 来对整个方法进行加锁,就例如下面这样。这种方式是解决了并发的问题,但是锁的粒度比较高,每次调用 GetInstance 方法的时候都需要获得锁才能获得 instance 实例,如果在调用频率比较高的场景下性能就不会很好。那有什么方式可以解决嘛?让我们接着往下看吧

var?mutex?sync.Mutexvar?instance?*Singletontype?Singleton?struct?{ }func?GetInstance()?*Singleton?{ mutex.Lock()defer?mutex.Unlock()if?instance?==?nil?{ ?instance?=?&Singleton{ }}return?instance}Double Check

       ä¸ºäº†è§£å†³é”çš„粒度问题,我们可以使用 Double Check 的方式来进行解决,例如下面的代码,第一次判断 instance == nil 之后需要进行加锁操作,然后再第二次判断 instance == nil 之后才能创建实例。这种方式对比上面的案例来说,锁的粒度更低,因为如果 instance != nil 的情况下是不需要加锁的。但是这种方式实现起来是不是比较麻烦,有没有什么方式可以解决呢?

var?mutex?sync.Mutexvar?instance?*Singletontype?Singleton?struct?{ }func?GetInstance()?*Singleton?{ if?instance?==?nil?{ ?mutex.Lock()?defer?mutex.Unlock()?if?instance?==?nil?{ ?instance?=?&Singleton{ }?}}return?instance}使用 sync.Once

       å¯ä»¥ä½¿ç”¨ sync.Once 来实现单例的初始化逻辑,因为这个逻辑至多只会跑一次。推荐使用这种方式来进行单例的初始化,当然也可以使用饿汉式。

var?once?sync.Oncevar?instance?*Singletontype?Singleton?struct?{ }func?GetInstance()?*Singleton?{ once.Do(func()?{ ?instance?=?&Singleton{ }})return?instance}源码分析

       ä¸‹é¢å°±æ˜¯ sync.Once 包的源码,我删除了注释,代码不多,Once 数据结构主要由 done 和 m 组成,其中 done 是存储 f 函数是否已执行,m 是一个锁实例。

type?Once?struct?{ done?uint?//?f函数是否已执行mMutex?//?锁}func?(o?*Once)?Do(f?func())?{ if?atomic.LoadUint(&o.done)?==?0?{ ?o.doSlow(f)}}func?(o?*Once)?doSlow(f?func())?{ o.m.Lock()defer?o.m.Unlock()if?o.done?==?0?{ ?defer?atomic.StoreUint(&o.done,?1)?f()}}

       Do 方法

       ä¼ å…¥ä¸€ä¸ª function,然后 sync.Once 来保证只执行一次,在 Do 方法中使用 atomic 来读取 done 变量,如果是 0 ,就代码 f 函数没有被执行过,然后就调用 doSlow方法,传入 f 函数

       doShow 方法

       doShow 的第一个步骤就是先加锁,这里加锁的目的是保证同一时刻是能由一个 goruntine 来执行 doSlow 方法,然后再次判断 done 是否是 0 ,这个判断就相当于我们上面说的 DoubleCheck ,因为 doSlow 可能存在并发问题。然后执行 f 方法,然后执行使用 atomic 将 done 保存成 1。使用 DoubleCheck 保证了 f 方法只会被执行一次。

       æŽ¥ç€çœ‹ï¼Œé‚£å¯ä»¥è¿™æ ·å®žçŽ° sync.Once 嘛?

       è¿™æ ·ä¸æ˜¯æ›´ç®€å•ä¸€ç‚¹å˜›ï¼Œä½¿ç”¨åŽŸå­çš„ CAS 操作就可以解决并发问题呀,并发只执行一次 f 方法的问题是可以解决,但是 Do 方法可能并发,第一个调用者将 done 设置成了 1 然后调用 f 方法,如果 f 方法特别耗时间,那么第二个调用者获取到 done 为 1 就直接返回了,此时 f方法是没有执行过第二次,但是此时第二个调用者可以继续执行后面的代码,如果后面的代码中有用到 f 方法创建的实例,但是由于 f 方法还在执行中,所以可能会出现报错问题。所以官方采用的是Lock + DoubleCheck 的方式。

if?atomic.CompareAndSwapUint(&o.done,?0,?1)?{ f()}拓展

       æ‰§è¡Œå¼‚常后可继续执行的Once

       çœ‹æ‡‚了源码之后,我们就可以扩展 sync.Once 包了。例如 f 方法在执行的时候报错了,例如连接初始化失败,怎么办?我们可以实现一个高级版本的 Once 包,具体的 slowDo 代码可以参考下面的实现

func?(o?*Once)?slowDo(f?func()?error)?error?{ o.m.Lock()defer?o.m.Unlock()var?err?errorif?o.done?==?0?{ ?//?Double?Checkerr?=?f()if?err?==?nil?{ ?//?没有异常的时候记录done值atomic.StoreUint(&o.done,?1)}}return?err}

       å¸¦æ‰§è¡Œç»“果的 Once

       ç”±äºŽ Once 是不带执行结果的,我们不知道 Once 什么时候会执行结束,如果存在并发,需要知道是否执行成功的话,可以看下下面的案例,我这里是以 redis 连接的问题来进行说明的。Do 方法执行完毕后将 init 值设置成 1 ,然后其他 goruntine 可以通过 IsConnetion 来获取连接是否建立,然后做后续的操作。

type?RedisConn?struct?{ once?sync.Onceinit?uint}func?(this?*RedisConn)?Init()?{ this.once.Do(func()?{ ?//?do?redis?connection?atomic.StoreUint(&this.init,?1)})}func?(this?*RedisConn)?IsConnect()?bool?{ ?//?另外一个goroutinereturn?atomic.LoadUint(&this.init)?!=?0}