2017-06-25 49 views
1

背景:我需要使用計劃任務來掃描數據表(1分鐘掃描一次,或者30秒一次),數據表會增加記錄,第三個數據源中的數據表與收集作爲參數做一個Thing,這個事情所需的時間無法確定(一個http請求),修改後的每個數據庫記錄狀態完成後,避免再次掃描下一次查詢時出現。IJob實現類Execute方法如何使用lock關鍵字?

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; 
     } 
    } 
} 

因爲多個工作觸發器短,並且DoWork的()方法執行時間是不可預測的,它可能會導致多個線程同時訪問persions變量。我如何使用鎖定語句來處理這個問題?

+0

**注意**:Execute()中有三個地方使用中間變量**進程** – qingyun1029

+0

您只想鎖定(personListLock){/ * ... * /}'?你可以看到這是如何工作的[這個問題](https://stackoverflow.com/questions/6029804/how-does-lock-work-exactly)。請注意,如果是這樣的話,那麼您的問題很可能會以重複的方式關閉 – Icepickle

+0

@lcepickle我希望這段代碼能夠在多線程中正常工作。謝謝 ! – qingyun1029

回答

0

我放三次訪問,以處理收集獨立的一類

public static class BaseProcessOperator<T> 
{ 
    static List<string> prevProcess = new List<string>(); 
    static object obj = new object(); 
    public static void AddRange(List<string> para) 
    { 
     lock (obj) 
     { 
      prevProcess.AddRange(para); 
     } 
    } 

    public static List<string> GetProcesses() 
    { 
     lock (obj) 
     { 
      return prevProcess; 
     } 
    } 

    public static void Remove<TParam>(List<TParam> currList, Func<TParam, string> fn) 
    { 
     if (currList != null && currList.Count() > 0) 
     { 
      lock (obj) 
      { 
       foreach (var i in currList) 
       { 
        var r = prevProcess.FirstOrDefault(s => s == fn(i)); 
        if (!string.IsNullOrWhiteSpace(r)) 
         prevProcess.Remove(r); 
       } 
      } 
     } 
    } 
} 

修改ScanJob.cs文件(不再直接使用process集,而是通過BaseProcessOperator<T>

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 => !BaseProcessOperator<ScanJob>.GetProcesses().Contains(s.Name)).ToList(); 

    Action<List<Person>> doWork = (s) => 
    { 
     BaseProcessOperator<ScanJob>.AddRange(s.Select(n => n.Name).ToList());//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 
     BaseProcessOperator<ScanJob>.Remove(pers, (s) => { return s.Name; }); 
    }, null); 

    Console.ReadKey(); 
} 
0

你可能會禁止同時執行Job,方法是加入DisallowConcurrentExecution屬性

[DisallowConcurrentExecution] 
public class ScanJob : IJob 
{ 

} 
+0

謝謝你讓我知道這個屬性! – qingyun1029

+0

我找到了一種不同的方式。 'var task = Task.Factory.StartNew(); task.Wait();' – qingyun1029