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


       

    课程大纲

       

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

       

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

       

    读写锁的分离

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

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

       

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

       

    1、多线程同时加共享锁

       

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

    elasticsearchconfigscripts目录下增加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、对共享锁进行解锁

    elasticsearchconfigscripts目录下增加 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 "

    },

    "script_stack": [],

    "script": "",

    "lang": "groovy"

    }

    },

    "status": 400

    }

       

    6、解锁排他锁

       

    DELETE /fs/lock/1

       

  • 相关阅读:
    微信小店 API 手册
    解密微信介入智能硬件的逻辑
    秒“增”微信粉丝12亿的方法
    微信公众平台开发(99) 自定义菜单获取OpenID
    微信企业号
    微信电商再侵袭,腾讯要革淘宝的命
    微信公众平台开发(98) UnionID
    微信公众平台开发(97) 图文消息
    微信公众平台开发(96) 多个功能整合
    微信公众平台开发(95) 世界杯赛程
  • 原文地址:https://www.cnblogs.com/liuqianli/p/8542134.html
Copyright © 2020-2023  润新知