当前位置:   article > 正文

ObservableCollection 集合的线程不安全导致的数据重复错误及解决办法。_observablecollection线程安全

observablecollection线程安全

   

 实际项目中,应用到了线程运作:

    如采集一个数据调用CatchDataByDay方法:

          Task.Run(() => CatchDataByDay());

    虽然利用代码2,判断数据是否重复。意图只保存不重复数据。但仍出现重复现象。

 

  一、Lock的方法
 

    1.保存数据的集合 ObservableCollection

  1. private ObservableCollection<Race> _RaceCollect;
  2. public ObservableCollection<Race> RaceCollect //用于保存数据的集合,并向UI通知更新
  3. {
  4. get { return this._RaceCollect; }
  5. set
  6. {
  7. this._RaceCollect = value;
  8. RaisePropertyChanged(() => RaceCollect);
  9. }
  10. }

    代码1:如下代码向RaceCollect集合中添加新数据,为防止集合被篡改,所以此处使用了lock(object)

  1. private void CatchDataByDay()
  2. {
  3. //此处省无关代码。
  4. string rsp = _http.HttpGet(url);
  5. JavaScriptSerializer serializer = new JavaScriptSerializer();
  6. var raceObject = serializer.Deserialize<Raceobject>(rsp);
  7. DataItem[] datas = raceObject.result.data;
  8. int n;
  9. for (int i = datas.Length - 1; i >= 0; i--)
  10. {
  11. var a = datas[i];
  12. //判断是否存在该数据
  13. if (ListContains(a.preDrawIssue)) continue;
  14. //
  15. Race race = new Race();
  16. //此处省无关代码。
  17. lock (locker)
  18. {
  19. _dispatcher.Invoke(new Action(() =>{_RaceCollect.Add(race);}));
  20. PickNumbersFromCollection();//挑选顺序出现的数字,并判断是否达到10个
  21. }
  22. }
  23. }//day
  24. //此处省无关代码。
  25. }

 代码2:_RaceCollect也进行了lock锁定,防止操作 List 时,内部计算可能会出现问题

  1. //判断集合中是否存在该数据
  2. private bool ListContains(string qh)
  3. {
  4. lock (locker)
  5. {
  6. var races = _RaceCollect.ToList<Race>();
  7. var ar = (from x in races where (x.QH.ToString().Trim() == qh.Trim()) select x).ToArray();
  8. if (ar == null || ar.Count() == 0)
  9. return false;
  10. else return true;
  11. }
  12. // 异常:System.ArgumentException: 目标数组的长度不够。请检查 destIndex 和长度以及数组的下限
  13. // 原因:List<T> 集合不是线程安全的,在并发操作 List 时,内部计算可能会出现问题
  14. }

二、其他解决办法

1。替代方法1

AsyncObservableCollection 继承自ObservableCollection类,可替代其使用。

  1. using System.Collections.Generic;
  2. using System.Collections.ObjectModel;
  3. using System.Collections.Specialized;
  4. using System.ComponentModel;
  5. using System.Threading;
  6. namespace Airship
  7. {
  8. /// <summary>
  9. /// 线程安全的集合,将ObservableCollection替换掉即可
  10. /// </summary>
  11. /// <typeparam name="T"></typeparam>
  12. public class AsyncObservableCollection<T> : ObservableCollection<T>
  13. {
  14. //获取当前线程的SynchronizationContext对象
  15. private SynchronizationContext _synchronizationContext = SynchronizationContext.Current;
  16. public AsyncObservableCollection() { }
  17. public AsyncObservableCollection(IEnumerable<T> list) : base(list) { }
  18. protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
  19. {
  20. if (SynchronizationContext.Current == _synchronizationContext)
  21. {
  22. //如果操作发生在同一个线程中,不需要进行跨线程执行
  23. RaiseCollectionChanged(e);
  24. }
  25. else
  26. {
  27. //如果不是发生在同一个线程中
  28. //准确说来,这里是在一个非UI线程中,需要进行UI的更新所进行的操作
  29. _synchronizationContext.Post(RaiseCollectionChanged, e);
  30. }
  31. }
  32. private void RaiseCollectionChanged(object param)
  33. {
  34. // 执行
  35. base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
  36. }
  37. protected override void OnPropertyChanged(PropertyChangedEventArgs e)
  38. {
  39. if (SynchronizationContext.Current == _synchronizationContext)
  40. {
  41. // Execute the PropertyChanged event on the current thread
  42. RaisePropertyChanged(e);
  43. }
  44. else
  45. {
  46. // Post the PropertyChanged event on the creator thread
  47. _synchronizationContext.Post(RaisePropertyChanged, e);
  48. }
  49. }
  50. private void RaisePropertyChanged(object param)
  51. {
  52. // We are in the creator thread, call the base implementation directly
  53. base.OnPropertyChanged((PropertyChangedEventArgs)param);
  54. }
  55. }
  56. }

2。替代2

  1. /// <summary>
  2. /// 如何使的 ObservableCollection 线程安全的?(How to make ObservableCollection thread-safe?)
  3. /// </summary>
  4. /// <typeparam name="T"></typeparam>
  5. public class MTObservableCollection<T> : ObservableCollection<T>
  6. {
  7. public override event NotifyCollectionChangedEventHandler CollectionChanged;
  8. protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
  9. {
  10. NotifyCollectionChangedEventHandler CollectionChanged = this.CollectionChanged;
  11. if (CollectionChanged != null)
  12. foreach (NotifyCollectionChangedEventHandler nh in CollectionChanged.GetInvocationList())
  13. {
  14. DispatcherObject dispObj = nh.Target as DispatcherObject;
  15. if (dispObj != null)
  16. {
  17. Dispatcher dispatcher = dispObj.Dispatcher;
  18. if (dispatcher != null && !dispatcher.CheckAccess())
  19. {
  20. dispatcher.BeginInvoke(
  21. (Action)(() => nh.Invoke(this,
  22. new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
  23. DispatcherPriority.DataBind);
  24. continue;
  25. }
  26. }
  27. nh.Invoke(this, e);
  28. }
  29. }

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/114551
推荐阅读
相关标签
  

闽ICP备14008679号