利用pointer, atomic原子操作.实现并发只获取一个操作对象.
import (
"fmt"
"sync/atomic"
"testing"
"time"
"unsafe"
)
//使用自旋获取对象. 保证只有一个对象.
type EtcdClient struct {
username string
password string
id int
}
func NewEtcdClient() *EtcdClient {
return &EtcdClient{
username:"etcd",
password:"root!root",
id: 100,
}
}
var etcdClientPointer unsafe.Pointer
func Client() *EtcdClient {
for {
p := (*EtcdClient)(atomic.LoadPointer(&etcdClientPointer)) //如果指针存在则直接返回
if p != nil {
return p
}
//不存在则创建
c := NewEtcdClient()
//使用比较并载入操作
if !atomic.CompareAndSwapPointer(&etcdClientPointer, nil, unsafe.Pointer(&c)) {
time.Sleep(time.Nanosecond * 10) //休10纳秒
continue
}
return c
}
}
测试用例
获取得地址是一样的.
func TestNewEtcdClient(t *testing.T) {
for i := 0;i < 10; i ++ {
go func(i int) {
fmt.Printf("%d, %p\n",i, Client())
}(i)
}
time.Sleep(time.Second)
}
结果
0xc000062240 #这个地址与下面地址不一样, 这是因为这个地址是对象实际存储的地址
0xc000006018 # 以下地址是Pointer指针存储空间的地址.
0xc000006018
0xc000006018
0xc000006018
0xc000006018
0xc000006018
0xc000006018
0xc000006018
0xc000006018