Go sync 锁

发布时间: 更新时间: 总字数:734 阅读时间:2m 作者: 分享 复制网址

介绍Golang中sync库中的各种锁的使用。

介绍

  • sync.Cond 条件锁
  • sync.Map 线程安全的 Map
  • sync.Mutex 互斥锁
  • sync.Once 只执行一次的锁
  • sync.Pool 对象池
  • sync.atomic 原子锁
  • sync.RWMutex 读写互斥锁
    • Lock|Unlock
    • RLock|RUnlock
  • sync.WaitGroup 等待组锁,用来计数

示例

Once 示例

sync.Once 修改的函数只能执行一次,一般定义为全局的,用在项目启动时限制一次性的初始化函数。

package main

import (
	"fmt"
	"sync"
)

func main() {
	var once sync.Once // 需要传递一个函数进去
	fmt.Printf("%T %#v\n", once, once)

	for i := 0; i < 10; i++ {
		once.Do(func() {
			fmt.Println(i)
		})
	}

	// Output:
	//sync.Once sync.Once{done:0x0, m:sync.Mutex{state:0, sema:0x0}}
	//0
}

Map 示例

sync.Map 是 Go 的 map[interface{}]interface{} 类型,但对于多个 goroutine 的并发使用是安全的,不需要额外的锁定或协调。

package main

import (
	"fmt"
	"sync"
)

func main() {
	var m sync.Map
	m.Store("k1", "str")
	m.Store("k2", 2)

	if v, ok := m.Load("k1"); ok {
		fmt.Println(v.(string), ok)
	} else {
		fmt.Println(ok)
	}

	if v, ok := m.Load("k2"); ok {
		fmt.Println(v.(int), ok)
	} else {
		fmt.Println(ok)
	}

	if v, ok := m.Load("k10"); ok {
		fmt.Println(v, ok)
	} else {
		fmt.Println(ok)
	}

	m.Delete("k1")
	if v, ok := m.Load(("k1")); ok {
		fmt.Println(v.(string), ok)
	} else {
		fmt.Println(ok)
	}

	// Output:
	//str true
	//2 true
	//false
	//false
}

对象池

sync.Pool 是一组可以单独保存和检索的临时对象。

package main

import (
	"fmt"
	"sync"
)

func main() {
	p := sync.Pool{
		New: func() interface{} {
			fmt.Println("call new")
			return 1
		},
	}

	// 从池里获取一个
	x := p.Get()
	fmt.Printf("%T %#v\n", x, x)

	// 放回池
	p.Put(x)

	// 再次从池里获取,不调用新建
	x = p.Get()
	fmt.Printf("%T %#v\n", x, x)

	// 在调用会创建,池里已经没有了,会重新创建
	x = p.Get()
	fmt.Printf("%T %#v\n", x, x)

	// Output:
	//call new
	//int 1
	//int 1
	//call new
	//int 1
}

指定义对象池

package main

import (
	"fmt"
	"sync"
)

type New func() interface{}

type Pool struct {
	mutex   sync.Mutex
	objects []interface{} // 切片
	new     New
}

func NewPool(new New) *Pool {
	return &Pool{
		objects: make([]interface{}, 0),
		new:     new,
	}
}

func NewSizePool(new New, size int) *Pool {
	// 初始化池的数量
	objects := make([]interface{}, size)
	for i := 0; i < size; i++ {
		objects[i] = new()
	}

	return &Pool{
		objects: objects,
		new:     new,
	}
}

func (p *Pool) Get() interface{} {
	p.mutex.Lock()
	defer p.mutex.Unlock()

	var result interface{}

	if len(p.objects) > 0 {
		// 队列方式获取
		result = p.objects[0]
		p.objects = p.objects[1:]
		// 堆栈方式获取
		//l := len(p.objects)
		//result = p.objects[l-1]
		//p.objects = p.objects[:l-1]

		return result
	} else {
		// 如果没有就新建
		return p.new()
	}
}

func (p *Pool) Put(obj interface{}) {
	p.mutex.Lock()
	defer p.mutex.Unlock()

	p.objects = append(p.objects, obj)
}

func main() {
	p := NewPool(func() interface{} {
		fmt.Println("call new")
		return 1
	})

	// 从池里获取一个
	x := p.Get()
	fmt.Printf("%T %#v\n", x, x)

	// 放回池
	p.Put(x)

	// 再次从池里获取,不调用新建
	x = p.Get()
	fmt.Printf("%T %#v\n", x, x)

	// 在调用会创建,池里已经没有了,会重新创建
	x = p.Get()
	fmt.Printf("%T %#v\n", x, x)
	fmt.Println()

	p = NewSizePool(func() interface{} {
		fmt.Println("call new 2")
		return 2
	}, 2)
	for i := 0; i < 3; i++ {
		x = p.Get()
		fmt.Printf("%T %#v\n", x, x)
	}

	// Output:
	//call new
	//int 1
	//int 1
	//call new
	//int 1
	//
	//call new 2
	//call new 2
	//int 2
	//int 2
	//call new 2
	//int 2
}

最新评论
加载中...
Home Archives Categories Tags Statistics