public class OrderJob : IJob { private static readonly object LockObj = new object(); public void Execute(IJobExecutionContext context) { //判断是否可以获取到排它锁,如果获取不到,则跳出等待 var canEnter = Monitor.TryEnter(LockObj); if (!canEnter) return; lock (LockObj) { Log.Debug($"{Process.GetCurrentProcess().Id}:{Thread.CurrentThread.GetHashCode()}:{this.GetType().Name} : entered:{DateTime.Now:yyyy-MM-dd HH:mm:ss ffffff}"); Log.Debug($"{Process.GetCurrentProcess().Id}:{Thread.CurrentThread.GetHashCode()}:{this.GetType().Name} exited:{DateTime.Now:yyyy-MM-dd HH:mm:ss ffffff}"); } } }
以上代码,记录的日志表明,即使处于同一个进程ID下,这个lock完全无效,无法阻止其它线程同时进入lock区域
记录时间:2017-04-27 10:40:00 日志级别:DEBUG 出错路径:Himall.Service.Job.FightGroupJob.Execute
错误描述:1249476:88:FightGroupJob entered:2017-04-27 10:40:00 055398 出错方法:Execute
记录时间:2017-04-27 10:40:00 日志级别:DEBUG 出错路径:Himall.Service.Job.RefundJob.Execute
错误描述:1249476:89:RefundJob : entered:2017-04-27 10:40:00 056375 出错方法:Execute
记录时间:2017-04-27 10:40:00 日志级别:DEBUG 出错路径:Himall.Service.Job.RefundJob.Execute
错误描述:1249476:69:RefundJob : entered:2017-04-27 10:40:00 058328 出错方法:Execute
记录时间:2017-04-27 10:40:00 日志级别:DEBUG 出错路径:Himall.Service.Job.FightGroupJob.Execute
错误描述:1249476:35:FightGroupJob entered:2017-04-27 10:40:00 059305 出错方法:Execute
记录时间:2017-04-27 10:40:00 日志级别:DEBUG 出错路径:Himall.Service.Job.FightGroupJob.Execute
错误描述:1249476:149:FightGroupJob entered:2017-04-27 10:40:00 060281 出错方法:Execute
记录时间:2017-04-27 10:40:00 日志级别:DEBUG 出错路径:Himall.Service.Job.RefundJob.Execute
错误描述:1249476:148:RefundJob : entered:2017-04-27 10:40:00 061258 出错方法:Execute
记录时间:2017-04-27 10:40:00 日志级别:DEBUG 出错路径:Himall.Service.Job.FightGroupJob.Execute
错误描述:1249476:6:FightGroupJob entered:2017-04-27 10:40:00 063211 出错方法:Execute
记录时间:2017-04-27 10:40:00 日志级别:DEBUG 出错路径:Himall.Service.Job.RefundJob.Execute
错误描述:1249476:7:RefundJob : entered:2017-04-27 10:40:00 067118 出错方法:Execute
记录时间:2017-04-27 10:40:00 日志级别:DEBUG 出错路径:Himall.Service.Job.FightGroupJob.Execute
错误描述:1249476:149:FightGroupJob entered:2017-04-27 10:40:00 091533 出错方法:Execute
记录时间:2017-04-27 10:40:00 日志级别:DEBUG 出错路径:Himall.Service.Job.FightGroupJob.Execute
错误描述:1249476:88:FightGroupJob entered:2017-04-27 10:40:00 123760 出错方法:Execute
记录时间:2017-04-27 10:40:00 日志级别:DEBUG 出错路径:Himall.Service.Job.FightGroupJob.Execute
错误描述:1249476:35:FightGroupJob entered:2017-04-27 10:40:00 128643 出错方法:Execute
记录时间:2017-04-27 10:40:00 日志级别:DEBUG 出错路径:Himall.Service.Job.FightGroupJob.Execute
错误描述:1249476:6:FightGroupJob entered:2017-04-27 10:40:00 147199 出错方法:Execute
记录时间:2017-04-27 10:40:01 日志级别:DEBUG 出错路径:Himall.Service.Job.RefundJob.Execute
错误描述:1249476:89:RefundJob exited:2017-04-27 10:40:01 099384 出错方法:Execute
记录时间:2017-04-27 10:40:01 日志级别:DEBUG 出错路径:Himall.Service.Job.RefundJob.Execute
错误描述:1249476:69:RefundJob exited:2017-04-27 10:40:01 123799 出错方法:Execute
记录时间:2017-04-27 10:40:01 日志级别:DEBUG 出错路径:Himall.Service.Job.RefundJob.Execute
错误描述:1249476:148:RefundJob exited:2017-04-27 10:40:01 127705 出错方法:Execute
记录时间:2017-04-27 10:40:01 日志级别:DEBUG 出错路径:Himall.Service.Job.RefundJob.Execute
错误描述:1249476:7:RefundJob exited:2017-04-27 10:40:01 406036 出错方法:Execute
FightGroupJob?RefundJob?这些呢?
其次tryEnter如果返回true后已经进到临界区了,没必要再次lock。
但单就你给出的这个代码而言,如果确认在同一进程下是不会出现问题的。
都是类似的代码~再次LOCK不会影响,但是实际上就目前而言,进程ID一直,线程ID不一致,但是实际运行的结果就是不是预期的。
我追加lock的原因是我希望锁住这部分代码,其它同时进入的线程不要等待锁,所以有之前的判断
@心雨纷扬: 不要怀疑这个lock会出问题,如果这种玩意能出问题早玩完了。
建议还是检查代码
@Daniel Cai: 我想问的就是这个代码会出什么问题???我目前就是不知道这样的代码怎么会出问题。lock目前无效啊,日志也有。证明多个线程同时进入了lock区域~~~~~~完全摸不着头脑,所以才来提问。。。。
虽然我贴出的代码是orderjob的,其实所有job的形式都是一样的。但是最终这个一样会同时多次进入lock区域
@心雨纷扬: 如果你一直担心这个代码中未锁住的问题的话,你可以把场景最小化,比如在linqpad或者控制台写个demo,就你上面那个代码你拿多个线程来压下。(不过我可以先告诉你就你前面贴的代码是不会出现任何未lock住的问题,前提是单进程)
@心雨纷扬: ps下,单进程一个appdomain下。
@Daniel Cai: 我刚才已经找到了appdomain这个原因了,正在寻找解决方案
@心雨纷扬: 这种场景下不建议再用进程内的锁了。跨appdomain的lock可以做,但感觉比较蛋疼。
这块建议是做一步到位的分布式锁。要么你就上命名的mutex
Log.Debug 你应该在这里加锁,你在一个基类里加个锁 有何意义呢?
哪里有基类???这个是定时任务,根据输出日志,这个会多个线程同时进入这个job。然后造成一个数据被多次结算
如果从代码来看,应该会被锁住的,只是我想问,你为什么认为一定没锁住呢?因为不能获取锁的线程因为canEnter为false的原因已经返回了,而更晚一些执行的线程能获取到锁就执行了log,这个很合理,不能说明锁失效了。
我的锁是锁了全程啊,因为被多线程差不多同时执行,导致数据的判断字段尚未保存,最终导致结算的数据会出现重复。
我怎么看。都不觉得是LOCK无效,CPU速度是非常快的,好的CPU你这代码一秒内执行个百万次循环都可以。你在lock里面加上thread.sleep(1000);测试一下。看是不是一秒一条日志。
最终发现是形成了多个appdomain了,无法直接使用静态变量锁,产生多个appdomain的原因未知。
考虑更换分布式锁