首页 新闻 会员 周边

c# 如何针对特定的条件进行锁操作?

0
悬赏园豆:5 [待解决问题]

如题,例如:多个用户编号从1到10,我希望编号相同的用户在执行代码时可以线程同步,但是其他编号的可以插入进来,不需要同步,尝试了lock锁,但是lock会把所有线程同步处理,同一时间只能处理一个请求,结束以后才处理第二个请求,我的需求是同一用户线程同步,不同用户可以异步处理。想了半天,也找了很多资料,找不到相关的解决方案,求助大牛,这种场景怎么才能实现?

阿祖哥的主页 阿祖哥 | 初学一级 | 园豆:197
提问于:2018-11-22 16:36
< >
分享
所有回答(6)
-1

lock锁住编号就行,不要锁住同一个变量

jqw2009 | 园豆:2439 (老鸟四级) | 2018-11-22 16:46

不可以的,lock不可以锁值类型,锁字符串的话也是没有效果的,因为字符串有驻留机制;new一个包含用户编号的实体也是不行的,因为每次请求都是新的实体,跟之前的已经不是同一个实体了;我在想是不是解决方法的方向错了。。。

支持(0) 反对(0) 阿祖哥 | 园豆:197 (初学一级) | 2018-11-22 16:55

@阿祖哥: 可以的,你试试就知道了

string NO="1"
lock(NO)
{}
这样就可以的,你可以加延时测试下就可以了

支持(0) 反对(0) jqw2009 | 园豆:2439 (老鸟四级) | 2018-11-22 16:57

@jqw2009: 你看,我试过了的,这样的话,其实锁是没有作用的,同一用户的线程并不是同步,我希望的是 这个43的用户线程同步

支持(0) 反对(0) 阿祖哥 | 园豆:197 (初学一级) | 2018-11-22 17:03

@阿祖哥: 有个关键的东西你要加上去,明天再告诉你

支持(0) 反对(0) jqw2009 | 园豆:2439 (老鸟四级) | 2018-11-22 17:10

@jqw2009: 大哥,别这样好吗?有方案的话就尽快告诉我吧。。。

支持(0) 反对(0) 阿祖哥 | 园豆:197 (初学一级) | 2018-11-22 17:27
0

不同用户使用不同线程来处理呢?

rqx | 园豆:468 (菜鸟二级) | 2018-11-22 17:11

就是不同线程的

支持(0) 反对(0) 阿祖哥 | 园豆:197 (初学一级) | 2018-11-22 17:29
0

我fuck了半天,看结果是可以的,没毛病,你再多加点数据fuck一下看看

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace LockTest
{
    class Program
    {
        static void Main(string[] args)
        {
            FuckMe fuckMe = new FuckMe();

            List<Person> peopleSet1 = new List<Person>();
            List<Person> peopleSet2 = new List<Person>();

            for (int i = 0; i < 10; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    peopleSet1.Add(new Person { Id = i.ToString() ,Name = $"{i}-{j}" });
                    peopleSet2.Add(new Person { Id = i.ToString(), Name = $"{i}-{j}" });
                }
            }

            Thread t1 = new Thread(() =>
            {
                foreach (var item in peopleSet1)
                {
                    fuckMe.Fuck(item);
                }
            });

            Thread t2 = new Thread(() =>
            {
                foreach (var item in peopleSet2)
                {
                    fuckMe.Fuck(item);
                }
            });

            t1.Start();
            t2.Start();

            t1.Join();
            t2.Join();

            Console.ReadLine();
        }
    }

    class Person
    {
        public string Id { get; set; }
        public string Name { get; internal set; }
    }

    class FuckMe
    {
        private string[] _lockObjects = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };

        public void Fuck(Person person)
        {
            string lockObj = _lockObjects.First(l => l == person.Id);

            lock (lockObj)
            {
                Console.WriteLine($"begin fuck Id:{person.Id}, name:{person.Name}");
                Thread.Sleep(500);
                Console.WriteLine($"end fuck Id: {person.Id}, name:{person.Name}");
            }
        }
    }
}

_lockObjects 可以动态构建,我举例子写死了

会长 | 园豆:12401 (专家六级) | 2018-11-22 17:20

先感谢你哈,我这边试下尝尝咸淡先

支持(0) 反对(0) 阿祖哥 | 园豆:197 (初学一级) | 2018-11-22 17:31

你好,用你这种方式是可以的,但是有个问题我没搞懂,为什么我直接lock("43")不可以,用你这种方式就可以了呢?
还有个问题,我这个用户编号是不确定的,我不能把库里所有用户编号放在一个数组里,那只能在主方法里用list把当前编号加到队列里,再去过滤使用,总觉得怪怪的,请问有什么好方法么?

支持(0) 反对(0) 阿祖哥 | 园豆:197 (初学一级) | 2018-11-22 17:51

@阿祖哥: 可能内容相同的字符串实际上是两个不同的对象吧

支持(0) 反对(0) 会长 | 园豆:12401 (专家六级) | 2018-11-22 18:02

@阿祖哥: 没想到别的方法,虽然不好,胜过没有吧。不知道用户的规模多大啊

支持(0) 反对(0) 会长 | 园豆:12401 (专家六级) | 2018-11-22 18:03

@阿祖哥: 或者这样也行啊,你把当前正在进行的用户的编号存起来,每次有用户来执行,你就看看这个用户的编号是否已经存在了,没有则执行,有就return了,把判断的代码放了lock里。不知道你们具体的业务是什么样的,把所有的用户放了队列,判断出队的用户可以执行不,可以的话就执行,不可以的话再如队

支持(0) 反对(0) 会长 | 园豆:12401 (专家六级) | 2018-11-22 18:07

@会长: 目前好像也只能这样了,业务主要是为了解决用户领取优惠券的时候,要检查是否已经领过优惠券,这个逻辑比较耗时,连续多次调用接口的话,会导致校验失败,所以相同用户领取的时候需要线程同步,但是不影响其他用户领取优惠券。
用户量有100万左右,我现在打算过1分钟就清空list(因为同个用户连续多次调用接口不会超过1分钟),这样应该没问题

支持(0) 反对(0) 阿祖哥 | 园豆:197 (初学一级) | 2018-11-22 19:14

@阿祖哥: 个人认为,这个方案不是很好,从运行结果上是OK

但是百万级别的数据,如果是发生高并发,算上用户的重复操作,那么瞬建最大并发容量至少需要达到1万以上,在面临高并发的时候,性能开销堪忧;

优先你需要考虑你的list的线程安全,多个线程同时读写一个不锁的list,那么如果两个同样的id同时去list里查询,那么都会返回无数据。庞大的list给内存和GC带来的负担外,每次在庞大的list中进行字符串匹配也会成为性能上的障碍。

最重要的是你如何保证每个ID在list中的生存周期独立,这个很重要,例如id=100第一次进来,被压入list,此时你的公共的1分钟到,清空list,马上第二次id=100的请求又进来。产生错误的并发数据。

支持(0) 反对(0) 写代码的相声演员 | 园豆:517 (小虾三级) | 2018-11-26 15:12
0

来一个字典,把编号做为Key,new Object()作为Value,lock的是value就好了,别使用string为作lock对象。

jiulang | 园豆:437 (菜鸟二级) | 2018-11-23 19:39
0

来,我给楼主一个思路。
设置10个static object锁,并行10个线程,每个线程都锁一个不同的锁,这样请求进来会排成10个队列,既能同时处理10个请求,又能锁住你想要锁的那一类请求。

Eysa | 园豆:62 (初学一级) | 2018-11-30 18:06
0

我也遇到了同样的问题,使用Mutex可以很简单的解决这个问题,并发的时候,相同用户id的线程就会排队执行

zhut96 | 园豆:210 (菜鸟二级) | 2019-07-18 18:10
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册