66.基于共享锁和排他锁实现悲观锁并发控制

   

课程大纲

   

一、共享锁和排他锁的说明

   

  • 共享锁:这份数据是共享的,可以多个线程同时过来获取同一个数据的,然后对这个数据执行读操作。
  • 排他锁:是排他的操作,只能一个线程获取排他锁,然后执行增删改操作。

   

读写锁的分离

如果只是要读取数据的话,那么任意多个线程都可以同时读取数据,每个线程都可以加一个共享锁,但是这个时候,如果有线程要修改数据,那么这个线程就会尝试加排他锁,排他锁会跟共享锁互斥,也就是说,如果有线程加了共享锁,那么就不加排他锁,此时这个线程就必须等待共享锁释放。

这就是说,如果有线程在读数据,就不允许其他线程修改数据反之,也是一样的。如果线程在修改数据,就是加了排他锁。那么其他线程过来要修改数据,也会尝试加排他锁,此时会失败,同时只能有一个线程修改数据。同理,如果此时有线程读取数据,那么会尝试加共享锁,此时也会失败,因为共享锁和排他锁是冲突的。

   

二、共享锁和排他锁的实验

   

1、多线程同时加共享锁

   

有线程读数据,其他线程也能过来读数据

\elasticsearch\config\scripts\目录下增加judge-lock-2.groovy脚本文件,文件内容为:if (ctx._source.lock_type == 'exclusive') { assert false }; ctx._source.lock_count++

   

1增加一个共享锁

POST /fs/lock/1/_update

{

"upsert": {

"lock_type": "shared",

"lock_count": 1

},

"script": {

        "lang": "groovy",

        "file": "judge-lock-2"

}

}

   

2其他线程再一次增加共享锁:

POST /fs/lock/1/_update

{

"upsert": {

"lock_type": "shared",

"lock_count": 1

},

"script": {

        "lang": "groovy",

        "file": "judge-lock-2"

}

}

   

3查看共享锁信息

GET /fs/lock/1

   

{

"_index": "fs",

"_type": "lock",

"_id": "1",

"_version": 2,

"found": true,

"_source": {

"lock_type": "shared",

"lock_count": 2

}

}

   

由上可以看出,对于同一份数据,可以由不同的线程增加共享锁。

   

2、在有共享锁的情况下,其他线程加排他锁

1)再加排他锁

PUT /fs/lock/1/_create

{ "lock_type": "exclusive" }

排他锁用的不是upsert语法,用的是create语法,要求lock必须不能存在,也就是说要求上锁的线和是第一个上锁的,此时已有共享锁存在,显然lock这个type是存在的,所以会报错。

{

"error": {

"root_cause": [

{

"type": "version_conflict_engine_exception",

"reason": "[lock][1]: version conflict, document already exists (current version [3])",

"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",

"shard": "3",

"index": "fs"

}

],

"type": "version_conflict_engine_exception",

"reason": "[lock][1]: version conflict, document already exists (current version [3])",

"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",

"shard": "3",

"index": "fs"

},

"status": 409

}

   

3、对共享锁进行解锁

\elasticsearch\config\scripts\目录下增加 unlock-shared.groovy脚本文件,文件内容为 if (--ctx.source.lock_count==0){ctx.op="delete"}

   

POST /fs/lock/1/_update

{

"script": {

        "lang": "groovy",

        "file": "unlock-shared"

}

}

   

连续解锁2次,此时共享锁就彻底没了。每次解锁一个共享锁,就对lock_count先减1,如果减了1之后是0,那么说明所有的共享锁都解锁完了,此时就就将/fs/lock/1删除,就彻底解锁所有的共享锁。在我的电脑上没有实验成功错误信息如下:

{

"error": {

"root_cause": [

{

"type": "remote_transport_exception",

"reason": "[SsqRO_3][127.0.0.1:9300][indices:data/write/update[s]]"

}

],

"type": "illegal_argument_exception",

"reason": "failed to execute script",

"caused_by": {

"type": "script_exception",

"reason": "error evaluating unlock-shared",

"caused_by": {

"type": "null_pointer_exception",

"reason": "Cannot get property 'lock_count' on null object"

},

"script_stack": [],

"script": "",

"lang": "groovy"

}

},

"status": 400

}

   

   

4、在已有排他锁的情况下,其他线程再加排他锁

   

PUT /fs/lock/1/_create

{ "lock_type": "exclusive" }

   

其他线程同时加锁

   

PUT /fs/lock/1/_create

{ "lock_type": "exclusive" }

错误信息

{

"error": {

"root_cause": [

{

"type": "version_conflict_engine_exception",

"reason": "[lock][1]: version conflict, document already exists (current version [7])",

"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",

"shard": "3",

"index": "fs"

}

],

"type": "version_conflict_engine_exception",

"reason": "[lock][1]: version conflict, document already exists (current version [7])",

"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",

"shard": "3",

"index": "fs"

},

"status": 409

}

   

5、在已有排他锁的情况下,其他线程加共享锁

   

POST /fs/lock/1/_update

{

"upsert": {

"lock_type": "shared",

"lock_count": 1

},

"script": {

        "lang": "groovy",

        "file": "judge-lock-2"

}

}

   

{

"error": {

"root_cause": [

{

"type": "remote_transport_exception",

"reason": "[4onsTYV][127.0.0.1:9300][indices:data/write/update[s]]"

}

],

"type": "illegal_argument_exception",

"reason": "failed to execute script",

"caused_by": {

"type": "script_exception",

"reason": "error evaluating judge-lock-2",

"caused_by": {

"type": "power_assertion_error",

"reason": "assert false\n"

},

"script_stack": [],

"script": "",

"lang": "groovy"

}

},

"status": 400

}

   

6、解锁排他锁

   

DELETE /fs/lock/1

   

posted @ 2018-03-10 21:28  outback123  阅读(183)  评论(0编辑  收藏  举报