【发布时间】:2017-06-26 22:32:34
【问题描述】:
背景:我需要使用定时任务扫描数据表(1分钟扫描一次,或者30秒扫描一次),数据表会增加记录,数据表在第三个数据源,以collection作为参数做一个Thing,这个事情需要的时间无法确定(一个http请求),完成后修改每个数据库记录的状态,避免下次再次扫描当查询出来时。
public class ScanJob : IJob
{
//Simulation of the data table, the reality of his records will not increase.
public static List<Person> persions = new List<Person>
{
new Person() { Name = "aaa", Status = true },
new Person() { Name = "bbb", Status = true },
new Person() { Name = "ccc", Status = true },
new Person() { Name = "ddd", Status = true },
new Person() { Name = "eee", Status = true },
};
//Intermediate variable, to avoid the previous has not yet ended, the next time has begun
public static List<string> process = new List<string>();
public void Execute(IJobExecutionContext context)
{
//Equivalent to a database query
var pers = persions.Where(s => s.Status).ToList();
//Exclude the object that was executed the previous time
pers = pers.Where(s=> !process.Contains(s.Name)).ToList();
Action<List<Person>> doWork = (s) =>
{
process.AddRange(s.Select(n => n.Name));//Add to intermediate variable
DoWork(s);//Do something that can not be expected time (http request)
};
doWork.BeginInvoke(pers, (str) =>
{
//After DoWork() ends, organize the intermediate variables
if (pers != null && pers.Count() > 0)
{
foreach (var i in pers)
process.Remove(i.Name);
}
}, null);
Console.ReadKey();
}
public void DoWork(List<Person> _pers)
{
Thread.Sleep(1000 * 60 * 1 + 1000 * 10);//Simulate http requests (One minute 10 seconds)
var firstPer = persions.Where(s => s.Status).FirstOrDefault();
if (firstPer != null)
{
//Simulation to modify the table record
firstPer.Status = false;
}
}
}
由于多个job触发时间较短,DoWork()方法执行时间不可预测,可能会导致多个线程同时访问persions变量。如何使用 lock 语句来处理这个问题?
【问题讨论】:
-
注意:Execute()中有三个地方用到了中间变量process
-
你只想
lock (personListLock) { /* ... */ }?你可以在this question 上看到它是如何工作的。请注意,如果这是一个,很可能您的问题将作为重复项关闭 -
@lcepickle 我希望这段代码在多线程中正常工作。谢谢!
-
@Icepickle 感觉我的问题和你给出的参考有点不一样,我需要知道在我的整个代码环境中,如何使用lock来保证多线程的安全,逻辑是正确的。 (可能我的代码之前需要调整一下,但是怎么调整呢?)
标签: c# quartz.net