程序员过关斩将--并发控制中的一个小提醒

共 1730字,需浏览 4分钟

 ·

2020-12-27 07:35

首先这是一篇快餐文,听说现在年轻人就喜欢快餐,不知道是真是假

稍微写过程序的同学都知道并发中最难的就是资源的竞争问题,说的白话一点,其实是数据一致性的问题。最常见的莫过于数据库的Insert和Update操作,对于同一条数据的多个update操作,其实DB在内部利用锁机制把请求顺序化了,换句话说,数据库已经帮你控制好了并发,使应用程序不会出现相互覆盖的操作。举个简单例子,假如用户账号里有100元钱,这个时候有两条update语句

update table set 余额=余额-10  where userId=100
update table set 余额=余额-20  where userId=100

无论如何并发执行两条sql,你会发现结果总是正确的,用于的余额总是70。如果按照对于资源竞争的理解,如果没有控制机制,总会有几率出现余额为90或者80的情况。这就是数据库的魅力,关系型数据库在一致性ACID这方面做的很好,这也是我提倡用DB事物代替分布式事务,少用分布式事务的原因之一。另外以前写过一篇关于数据库悲观锁和乐观锁的文章,感兴趣的同学可以去赐教:

数据库的乐观锁和悲观锁并非真实的锁

言归正传,在DB的上层应用中,也避免不了对某些资源的并发修改,而大部分编程语言也提供了锁机制,比如c#的Lock语法,java中的synchronized 等。然而今天的话题确实另外一码事,居然说了这么一大堆废话,意不意外?

请看一下程序,我相信很多同学也写过

static object ObjLock = new object();
        public static void Run(int Id)
        {
            //开始处理的程序100行
            lock (ObjLock)
            {
                //业务处理程序1000 行
            }
            //结尾程序100 行
        }
image

如果并发比较大的话,你的老板又要跳脚杀一个程序员祭天了。以上代码有没有问题呢?当然有,要不然我发它干嘛

站在业务功能的角度来说,以上代码实现所需业务,而且进行资源竞争问题的处理没有问题,加入lock方法体中的代码执行时间过长,在稍微有一些并发的情况下,程序会非常慢。原因在于lock这里。

在编写并发的代码中,我们要时刻记住,我们要控制的是对同一个资源的并发请求做控制,对应以上代码,不难发现,其实相当于对所有的资源竞争做了顺序化,这样是得不偿失的。

怎么修改呢?我们可以对每个资源实现一个lock

 static ConcurrentDictionary LockDic = new System.Collections.Concurrent.ConcurrentDictionary();
     
        public static void Run(int Id)
        {
            //根据要控制的资源id,进行分别控制
           var lockObj= LockDic.GetOrAdd("资源的标示",(k)=>{ return new object(); });
            //开始处理的程序100行
            lock (lockObj)
            {
                //业务处理程序1000 行
            }
            //结尾程序100 行
        }

每个竞争资源一个lock,这样就能实现多个资源的并行处理,你们说对不对?




程序员过关斩将--请不要误会redis 6.0 的多线程


程序员过关斩将--论系统设计的高可扩展性


程序员过关斩将--从未停止过的系统架构设计步伐


浏览 42
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报