64.基于全局锁实现悲观锁并发控制

Posted Outback

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了64.基于全局锁实现悲观锁并发控制相关的知识,希望对你有一定的参考价值。

主要知识点

  • 悲观锁的简要说明
  • 全局锁实验
  • 全局锁的优缺点及适用场景

   

一、悲观锁的简要说明

   

悲观锁不象悲观锁那样基于version进行并发控制,而是直接加锁,加锁后只有加锁的线程可以使用该index(type),其他线程不同同时使用,只有当这个线程解锁之后,其他线程才能恢复使用,本节合文件系统建模的这个案例,把悲观锁的并发控制,3种锁粒度,都给大家仔细讲解一下。其中最粗的一个粒度就是全局锁,也就是直接锁整个index。现假设/workspace/projects/helloworld目录下有一个名为README.txt的文件。如果有多个线程要并发地修改/workspace/projects/helloworld下的README.txt的文件名。此时如果不加锁,纯并发的话,先执行的修改操作被后执行的修改操作给覆盖了。

乐观锁的做法是先获得版本号(get current version),然后带着这个current version去执行修改,如果一旦发现数据已经被别人给修改了,version号跟之前自己获取的已经不一样了, 就必须重新获取新的version号再次尝试修改。直到一致为止。

悲观锁的做是在修改之前就直接就尝试给这条数据加个锁,如果加锁不成功就等待。继续加锁,如果加锁成功,此时就只有这一个线程能执行的操作,其他线程不能执行操作。

   

第一种锁:全局锁,直接锁掉整个fs index

   

二、全局锁实验

1、加锁

PUT /fs/lock/global/_create

{}

   

  • fs: 你要上锁的那个index
  • lock: 就是你指定的一个对这个index上全局锁的一个type。也就是说加锁也是创建一个type,只不过这个type的作用就是用来加锁。
  • global: 就是你上的全局锁对应的这个docidglobal就是lockid
  • _create:强制必须是创建操作,也就是说必须是本线程新建锁,如果其他线程已创建锁,那么创建失败,则会报错。

   

{

"_index": "fs",

"_type": "lock",

"_id": "global",

"_version": 1,

"result": "created",

"_shards": {

"total": 2,

"successful": 1,

"failed": 0

},

"created": true

}

   

另外一个线程同时尝试上锁就会报错,但是我在第二个线程上执行修改更新操作会成功,不知为会么?

这里只有当第二个线程上同样的锁(id相同)才会报错,也就是说第二个线程也执行如下语句才会报错,

PUT /fs/lock/global/_create

{}

如果第二个线程执行这样的语句,就不会报错,

PUT /fs/lock/fuck/_create

{}

   

   

然后可以执行各种操作。。。

   

POST /fs/file/1/_update

{

"doc": {

"name": "README1.txt"

}

}

   

2、解锁

解锁其实就是删除对应id的doc

   

DELETE /fs/lock/global

   

三、全局锁的优缺点及适用场景

   

优点:操作非常简单,非常容易使用,成本低

缺点:直接就把整个index给上锁了,这个时候对index中所有的doc的操作,都会被block住,导致整个系统的并发能力很低。通过和自已的实验,实际不会block住其他线程,

适用场景:上锁解锁的操作不是频繁,然后每次上锁之后,执行的操作的耗时不会太长,用这种方式,方便

   

   

以上是关于64.基于全局锁实现悲观锁并发控制的主要内容,如果未能解决你的问题,请参考以下文章

Elasticsearch 基于乐观锁的并发控制 --- 2022-04-03

并发控制:乐观锁 悲观锁

悲观锁 乐观锁

什么是乐观锁,什么是悲观锁,如何实现

mysql在django中开启事务,实现悲观锁和乐观锁

乐观锁vs悲观锁