EntityFramework用法探索(七)线程安全实践

简介:

前文中,我们通过Unity来注册各种类型和WiringUp。

复制代码
 1       IUnityContainer container = new UnityContainer()
 2         .RegisterType(typeof(IRepository<>), typeof(Repository<>), new ContainerControlledLifetimeManager())
 3         .RegisterType<IUnitOfWork, UnitOfWork>(new ContainerControlledLifetimeManager())
 4         .RegisterType<DbContext, RETAILContext>(new ContainerControlledLifetimeManager())
 5         .RegisterType<DbContextAdapter>(new ContainerControlledLifetimeManager())
 6         .RegisterType<IObjectSetFactory, DbContextAdapter>(new ContainerControlledLifetimeManager())
 7         .RegisterType<IObjectContext, DbContextAdapter>(new ContainerControlledLifetimeManager())
 8         .RegisterType<ICustomerRepository, CustomerRepository>(new ContainerControlledLifetimeManager());
 9 
10       UnityServiceLocator locator = new UnityServiceLocator(container);
11       ServiceLocator.SetLocatorProvider(() => locator);
12 
13       ICustomerRepository customerRepository = container.Resolve<ICustomerRepository>();
复制代码

但选择使用了ContainerControlledLifetimeManager对象生命周期管理器,其将每个对象存储为Singleton。这导致在多线程环境下会产生异常。

例如我们尝试在多线程条件下更新Customer表:

复制代码
 1       List<Task> tasks = new List<Task>();
 2       for (int i = 0; i < 16; i++)
 3       {
 4         DomainModels.Customer modifiedCustomer = Mapper.Map<DomainModels.Customer, DomainModels.Customer>(customer1);
 5         modifiedCustomer.Name = modifiedCustomer.Name + i;
 6 
 7         Task t = Task.Factory.StartNew(() =>
 8         {
 9           try
10           {
11             customerRepository.UpdateCustomer(modifiedCustomer);
12           }
13           catch (Exception ex)
14           {
15             Console.WriteLine("Exception occurred in thread " + Thread.CurrentThread.ManagedThreadId);
16             Console.WriteLine(ex.Message);
17           }
18         });
19         tasks.Add(t);
20       }
21       Task.WaitAll(tasks.ToArray());
复制代码

但由于我们仍然需要EntityFramework的Local功能,即在当前线程环境下始终使用当前上下文中的对象。我们可能还无法选择其他Unity对象生命期管理模型

此时,我们考虑一种新的方法,引入线程Scope功能,即在给定线程中,使用同一个UnityContainer来维护对象,这样间接利用的EntityFramework的上下文功能。

原理很简单,就是为每个线程生成一个单独的ChildUnityContainer。

复制代码
 1   public class UnityContainerScope : IDisposable
 2   {
 3     private static ConcurrentDictionary<int, bool> scopeMapping
 4       = new ConcurrentDictionary<int, bool>();
 5 
 6     protected UnityContainerScope()
 7     {
 8       ScopeId = Thread.CurrentThread.ManagedThreadId;
 9       scopeMapping.Add(ScopeId, true);
10     }
11 
12     public int ScopeId { get; private set; }
13     public static int ScopeCount { get { return scopeMapping.Count; } }
14 
15     public static UnityContainerScope NewScope()
16     {
17       return new UnityContainerScope();
18     }
19 
20     public static bool InScope(int scopeId)
21     {
22       return scopeMapping.ContainsKey(scopeId);
23     }
24 
25     public void Dispose()
26     {
27       UnityContainerDispatcher.DisposeContainer();
28       scopeMapping.Remove(ScopeId);
29     }
30   }
复制代码

这里同时需要一个UnityContainerDispatcher来负责为线程生成Container容器。

复制代码
 1   public static class UnityContainerDispatcher
 2   {
 3     private static IUnityContainer parentContainer = null;
 4     private static ConcurrentDictionary<int, IUnityContainer> containerMapping
 5       = new ConcurrentDictionary<int, IUnityContainer>();
 6 
 7     public static void InjectParentContainer(IUnityContainer unity)
 8     {
 9       if (unity == null)
10         throw new ArgumentNullException("unity");
11 
12       parentContainer = unity;
13     }
14 
15     public static IUnityContainer GetContainer()
16     {
17       int key = Thread.CurrentThread.ManagedThreadId;
18 
19       if (!UnityContainerScope.InScope(key))
20       {
21         throw new UnityContainerNotInScopeException(
22           string.Format(CultureInfo.InvariantCulture,
23           "The specified scope id [{0}] is not in scope.", key));
24       }
25 
26       if (!containerMapping.ContainsKey(key))
27       {
28         BuildUpContainer(key);
29       }
30 
31       return containerMapping.Get(key);
32     }
33 
34     public static void DisposeContainer()
35     {
36       int key = Thread.CurrentThread.ManagedThreadId;
37       IUnityContainer container = containerMapping.Remove(key);
38       if (container != null)
39       {
40         container.Dispose();
41       }
42     }
43 
44     private static void BuildUpContainer(int key)
45     {
46       if (parentContainer == null)
47         throw new InvalidProgramException("The parent container cannot be null.");
48 
49       IUnityContainer childContainer = parentContainer.CreateChildContainer();
50       containerMapping.Add(key, childContainer);
51     }
52   }
复制代码

在注入的根UnityContainer中,我们通过使用CreateChildContainer方法来获取一个新的Container,同时继承所有根容器的注册配置信息。这要求使用HierarchicalLifetimeManager生命期管理器

此时,我们的代码修改为,

复制代码
 1       IUnityContainer container = new UnityContainer()
 2         .RegisterType(typeof(IRepository<>), typeof(Repository<>), new HierarchicalLifetimeManager())
 3         .RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager())
 4         .RegisterType<DbContext, RETAILContext>(new HierarchicalLifetimeManager())
 5         .RegisterType<DbContextAdapter>(new HierarchicalLifetimeManager())
 6         .RegisterType<IObjectSetFactory, DbContextAdapter>(new HierarchicalLifetimeManager())
 7         .RegisterType<IObjectContext, DbContextAdapter>(new HierarchicalLifetimeManager())
 8         .RegisterType<ICustomerRepository, CustomerRepository>(new HierarchicalLifetimeManager());
 9 
10       UnityContainerDispatcher.InjectParentContainer(container);
11 
12       ICustomerRepository customerRepository = container.Resolve<ICustomerRepository>();
复制代码

创建多线程测试代码,

复制代码
 1       List<Task> tasks = new List<Task>();
 2       for (int i = 0; i < 16; i++)
 3       {
 4         DomainModels.Customer modifiedCustomer = Mapper.Map<DomainModels.Customer, DomainModels.Customer>(customer1);
 5         modifiedCustomer.Name = modifiedCustomer.Name + i;
 6 
 7         Task t = Task.Factory.StartNew(() =>
 8         {
 9           try
10           {
11             using (UnityContainerScope scope = UnityContainerScope.NewScope())
12             {
13               customerRepository.UpdateCustomer(modifiedCustomer);
14               Console.WriteLine("Modified " + modifiedCustomer.Name + " in thread " + Thread.CurrentThread.ManagedThreadId);
15             }
16           }
17           catch (Exception ex)
18           {
19             Console.WriteLine("Exception occurred in thread " + Thread.CurrentThread.ManagedThreadId);
20             Console.WriteLine(ex.Message);
21           }
22         });
23         tasks.Add(t);
24       }
25       Task.WaitAll(tasks.ToArray());
复制代码

测试结果表明已经可以安全的在多线程条件下工作了。

完整代码和索引

EntityFramework用法探索系列

完整代码下载






本文转自匠心十年博客园博客,原文链接:http://www.cnblogs.com/gaochundong/archive/2013/06/06/entityframework_usage_thread_scope.html,如需转载请自行联系原作者

目录
相关文章
|
2月前
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
231 0
|
23天前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
25天前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
103 6
|
25天前
|
安全 Java 开发者
Java中的多线程编程:从基础到实践
本文深入探讨了Java多线程编程的核心概念和实践技巧,旨在帮助读者理解多线程的工作原理,掌握线程的创建、管理和同步机制。通过具体示例和最佳实践,本文展示了如何在Java应用中有效地利用多线程技术,提高程序性能和响应速度。
58 1
|
1月前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####
|
1月前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
1月前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
1月前
|
Java UED
Java中的多线程编程基础与实践
【10月更文挑战第35天】在Java的世界中,多线程是提升应用性能和响应性的利器。本文将深入浅出地介绍如何在Java中创建和管理线程,以及如何利用同步机制确保数据一致性。我们将从简单的“Hello, World!”线程示例出发,逐步探索线程池的高效使用,并讨论常见的多线程问题。无论你是Java新手还是希望深化理解,这篇文章都将为你打开多线程的大门。
|
1月前
|
缓存 Java 调度
Java中的多线程编程:从基础到实践
【10月更文挑战第24天】 本文旨在为读者提供一个关于Java多线程编程的全面指南。我们将从多线程的基本概念开始,逐步深入到Java中实现多线程的方法,包括继承Thread类、实现Runnable接口以及使用Executor框架。此外,我们还将探讨多线程编程中的常见问题和最佳实践,帮助读者在实际项目中更好地应用多线程技术。
27 3
|
1月前
|
监控 安全 Java
Java多线程编程的艺术与实践
【10月更文挑战第22天】 在现代软件开发中,多线程编程是一项不可或缺的技能。本文将深入探讨Java多线程编程的核心概念、常见问题以及最佳实践,帮助开发者掌握这一强大的工具。我们将从基础概念入手,逐步深入到高级主题,包括线程的创建与管理、同步机制、线程池的使用等。通过实际案例分析,本文旨在提供一种系统化的学习方法,使读者能够在实际项目中灵活运用多线程技术。