CompletableFuture supplyAsync多线程使用entityManager
时间: 2025-02-07 12:08:05 浏览: 51
`CompletableFuture.supplyAsync()` 结合 `EntityManager` 使用涉及到 Java 的并发处理和持久化管理。这里我们将探讨如何安全地在多线程环境中使用 JPA (Java Persistence API) 的 `EntityManager` 来执行异步任务。
### 1. 理解 SupplyAsync
`supplyAsync(Supplier<U> supplier)` 是 `CompletableFuture` 类的一个静态工厂方法,它用于创建一个新的未完成的 CompletableFuture,并将其设置为由给定 Supplier 异步计算的结果值。这个操作是在 ForkJoinPool.commonPool() 中默认运行的;当然也可以指定自定义的 Executor 参数版本来控制线程池。
```java
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return "Hello World!";
});
```
当需要在这个供给函数内访问数据库时,则会牵涉到 EntityManager 实例。
### 2. 正确配置 EntityManagerFactory 和 ThreadLocal<EntityManager>
由于 `EntityManager` 并不是线程安全的对象,所以在每个工作单元开始时都应获取新的实例,在结束之后关闭之。推荐的方式是通过 @PersistenceUnit 注入 `EntityManagerFactory`, 然后利用 ThreadLocal 存储当前线程专属的 EntityManager:
```java
@PersistenceUnit(unitName="my-persistence-unit")
private EntityManagerFactory emf;
public void performDatabaseOperation() {
// 封装了从factory获得manager并放入ThreadLocal的过程
}
```
对于异步调用来说,可以封装一个辅助工具类或方法来进行上述流程简化。
### 3. 应用场景示例 - 利用SupplyAsync查询数据
考虑这样一个例子:我们需要在一个独立于主线程之外的任务中去检索一些用户信息并且返回结果集作为 Future 对象的一部分:
```java
private final static ThreadLocal<EntityManager> threadEntityManager =
new InheritableThreadLocal<>();
// ...
CompletableFuture<List<User>> fetchUsersAsync(Long userId){
return CompletableFuture.supplyAsync(()->{
try(EntityManager em=threadEntityManager.get()){
if(em == null)
throw new IllegalStateException("No entity manager for current thread");
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> rootEntry = cq.from(User.class);
// 构建查询条件...
TypedQuery<User> query =em.createQuery(cq);
List<User> users=query.getResultList();
return users;
}
});
}
```
注意这里的 `EntityManager` 获取是从之前提到过的 `ThreadLocal<EntityManager>` 变量中取得而不是直接创建新实例; 这样保证了同一个物理连接在整个事务期间一直有效直至其被提交或者回滚.
最后需要注意的是,在实际生产应用当中应当尽量减少长时间持有锁资源如 Session 或者 Connection ,避免造成不必要的性能瓶颈甚至死锁现象发生。
阅读全文
相关推荐

















