利用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