企业管理网站系统,建筑学是十大最烂专业之一吗,血液中心网站建设规范,seo模拟点击算法改变一个数值的三个步骤
把想修改的数值从某个地方取出来将取出来的数值修改为期望值把修改后的数值保存到原来的地方
问题
如果在做第2步时#xff0c;有另一个过程#xff08;进程或线程#xff09;对同一个数值进行同样的操作#xff08;取值、修改#xff09;…改变一个数值的三个步骤
把想修改的数值从某个地方取出来将取出来的数值修改为期望值把修改后的数值保存到原来的地方
问题
如果在做第2步时有另一个过程进程或线程对同一个数值进行同样的操作取值、修改那么当这两个过程都要做第3步的时候就肯定有一个过程是白干活的。
悲观锁
悲观的锁总认为会发生并发问题属于保守派。 如果想修改一个数值立马给这个数值上一把锁标明这个数值正在被修改谁也不能修改了然后才开始三步走在三步走的过程结束以后再把锁解除。
当有其他过程想要修改同一个数值时看到了锁就不进行三步走了而是选择等待当锁被解除了自己在数值也加一把锁然后开始三步走在三个步骤走完了也把锁解除。
乐观锁
乐观的锁总认为不会发生并发问题属于乐天派。
修改数据时不加锁正常进行1、2步在进行第3步的时候确认一下数值是否进行了修改如果被修改过放弃修改重新走一遍1、2、3步或者放弃对数值进行修改。
Go语言中的乐观锁与悲观锁
sync/atomic
Go语言有一个atomic包可以在不形成临界区和创建互斥量的情况下完成并发安全的值替换操作这个包应用的便是乐观锁的原理 但是这个包只支持int32/int64/uint32/uint64/uintptr这几种数据类型的一些基础操作,如增减、交换、载入、存储等
sync
Go语言中的sync包提供了各种锁如果使用了这个包基本就以悲观锁的工作模式了
go代码示例
package mainimport (fmtsyncsync/atomictime
)var (x int64mu sync.Mutexwg sync.WaitGroup
)// 普通函数 并发不安全
func Add() {xwg.Done()
}// 互斥锁, 并发安全性能低于原子操作
func muAdd() {mu.Lock()xmu.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