Go语言中乐观锁与悲观锁的具体使用

 更新时间:2024年01月09日 09:45:28   作者:别人家的孩子zyh  
乐观锁和悲观锁是两种思想,用于解决并发场景下的数据竞争问题,本文主要介绍了Go语言中乐观锁与悲观锁的具体使用,具有一定的参考价值,感兴趣的可以了解一下

改变一个数值的三个步骤

  • 把想修改的数值从某个地方取出来
  • 将取出来的数值修改为期望值
  • 把修改后的数值保存到原来的地方

问题

如果在做第2步时,有另一个过程(进程或线程)对同一个数值进行同样的操作(取值、修改),那么当这两个过程都要做第3步的时候,就肯定有一个过程是白干活的。

悲观锁

悲观的锁总认为会发生并发问题,属于保守派。
如果想修改一个数值,立马给这个数值上一把锁,标明这个数值正在被修改,谁也不能修改了;然后才开始三步走,在三步走的过程结束以后,再把锁解除。

当有其他过程想要修改同一个数值时,看到了锁就不进行三步走了,而是选择等待;当锁被解除了,自己在数值也加一把锁,然后开始三步走,在三个步骤走完了,也把锁解除。

乐观锁

乐观的锁总认为不会发生并发问题,属于乐天派。

修改数据时不加锁,正常进行1、2步,在进行第3步的时候,确认一下数值是否进行了修改,如果被修改过,放弃修改,重新走一遍1、2、3步(或者放弃对数值进行修改)。

Go语言中的乐观锁与悲观锁

sync/atomic

Go语言有一个atomic包,可以在不形成临界区和创建互斥量的情况下完成并发安全的值替换操作,这个包应用的便是乐观锁的原理
但是这个包只支持int32/int64/uint32/uint64/uintptr这几种数据类型的一些基础操作,如增减、交换、载入、存储等

sync

Go语言中的sync包提供了各种锁,如果使用了这个包,基本就以悲观锁的工作模式了

go代码示例

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

var (
	x  int64
	mu sync.Mutex
	wg sync.WaitGroup
)

// 普通函数, 并发不安全
func Add() {
	x++
	wg.Done()
}

// 互斥锁, 并发安全,性能低于原子操作
func muAdd() {
	mu.Lock()
	x++
	mu.Unlock()
	wg.Done()
}

// 原子操作,并发安全,性能高于互斥锁,只针对go中的一些基本数据类型使用
func AmAdd() {
	atomic.AddInt64(&x, 1)
	wg.Done()
}

func main() {
	// 原子操作atomic包
	// 加锁操作涉及到内核态的上下文切换, 比较耗时,代价高
	// 针对基本数据类型我们还可以使用原子操作来保证并发安全
	// 因为原子操作是go语言提供的方法,我们在用户态就可以完成,因此性能比加锁操作更好
	// go语言的原子操作由内置的库,sync/atomic完成

	start := time.Now()
	for i := 0; i < 10000; i++ {
		wg.Add(1)
		go Add() // 普通版Add函数不是并发安全的
		// go muAdd() // 加锁版Add函数,是并发安全的, 但是加锁性能开销大
		// go AmAdd() // 原子操作版Add函数,是并发安全的,性能优于加锁版
	}

	end := time.Now()
	wg.Wait()
	fmt.Println(x)
	fmt.Println(end.Sub(start))

}

参考博客1

参考博客2

到此这篇关于Go语言中乐观锁与悲观锁的具体使用的文章就介绍到这了,更多相关Go语言 乐观锁与悲观锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang实现多存储驱动设计SDK案例

    Golang实现多存储驱动设计SDK案例

    这篇文章主要介绍了Golang实现多存储驱动设计SDK案例,Gocache是一个基于Go语言编写的多存储驱动的缓存扩展组件,更多具体内容感兴趣的小伙伴可以参考一下
    2022-09-09
  • Golang如何将日志以Json格式输出到Kafka

    Golang如何将日志以Json格式输出到Kafka

    这篇文章主要介绍了Golang将日志以Json格式输出到Kafka的方法,这篇文章还会提供一种输出Json格式日志的方法,本文结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • go编译标签build tag注释里语法详解

    go编译标签build tag注释里语法详解

    这篇文章主要为大家介绍了go编译标签build tag注释里语法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • golang 实现json类型不确定时的转换

    golang 实现json类型不确定时的转换

    这篇文章主要介绍了golang 实现json类型不确定时的转换操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 利用go语言判断是否是完全二叉树

    利用go语言判断是否是完全二叉树

    这篇文章主要介绍了利用go语言判断是否是完全二叉树,当一个节点存在右子节点但是不存在左子节点这颗树视为非完全二叉树,通过利用GO语言判断来判断出否是完全二叉树,详细内容参考如下
    2022-05-05
  • gtoken替换jwt实现sso登录的排雷避坑

    gtoken替换jwt实现sso登录的排雷避坑

    这篇文章主要为大家介绍了gtoken替换jwt实现sso登录的排雷避坑,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • 浅析Go语言版本的forgery

    浅析Go语言版本的forgery

    使用过Python语言的朋友们可能使用过 forgery_py ,它是一个伪造数据的工具。这篇文章主要介绍了Go语言版本的forgery,需要的朋友可以参考下
    2018-08-08
  • 详解Go语言的内存模型及堆的分配管理

    详解Go语言的内存模型及堆的分配管理

    这篇笔记主要介绍Go内存分配和Go内存管理,会轻微涉及内存申请和释放,以及Go垃圾回收,文中有详细的代码示例以及图片介绍,需要的朋友可以参考下
    2023-05-05
  • golang 实现一个restful微服务的操作

    golang 实现一个restful微服务的操作

    这篇文章主要介绍了golang 实现一个restful微服务的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • go语言反射的基础教程示例

    go语言反射的基础教程示例

    这篇文章主要为大家介绍了go语言反射的基础教程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08

最新评论