java - 长时间运行的方法会导致竞争条件

标签 java hibernate spring race-condition

我对 hibernate 还比较陌生,所以请保持温柔。我在长时间运行的方法(约 2 分钟长)和更改存储在数据库中的对象上的状态字段的值时遇到问题。下面的伪代码应该有助于解释我的问题。

public foo(thing) {  
    if (thing.getStatus() == "ready") {
        thing.setStatus("finished");
        doSomethingAndTakeALongTime();
    } else {
        // Thing already has a status of finished. Send the user back a message.
    }
}

伪代码不需要太多解释。我希望 doSomethingAndTakeALongTime() 运行,但前提是它的状态为“就绪”。每当 doSomethingAndTakeALongTime() 完成需要 2 分钟并且事物状态字段的更改在离开 foo() 之前不会持久保存到数据库时,就会出现我的问题。因此,另一个用户可以在这 2 分钟内发出请求,if 语句将计算为 true。

我已经尝试过手动更新字段并刷新 session ,但似乎不起作用。我不知道从这里该怎么做,非常感谢任何帮助。

PS:我的 hibernate session 由 spring 管理。

最佳答案

基本上,您需要让它在单独的线程中运行,以使该方法立即返回。否则它确实会阻塞,直到长时间运行的任务完成。您可以将实体本身传递给线程,以便它可以自行更新状态。这是使用简单Thread的基本启动示例。

public class Task extends Thread {
    private Entity entity;
    public Task(Entity entity) {
        this.entity = entity;
    }
    public void run() {
        entity.setStatus(Status.RUNNING);
        // ...
        // Long running task here.
        // ...
        entity.setStatus(Status.FINISHED);
    }
}

public synchronized void foo(Entity entity) {
    if (entity.getStatus() == Status.READY) {
        new Task(entity).start();
    } else {
        // ...
    }
}

状态位于 enum 中您甚至可以使用 switch 语句来代替 if/else

    switch (entity.getStatus()) {
        case READY: 
            new Task(entity).start();
            break;
        case RUNNING:
            // It is still running .. Have patience!
            break;
        case FINISHED:
            // It is finished!
            break;
    }            

为了对正在运行的线程进行更强大的控制,您可能需要考虑 ExecutorService反而。由此,您可以控制最大线程数并指定超时。

关于java - 长时间运行的方法会导致竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2917156/

相关文章:

java - 使用 CommonsMultipartResolver 上传多个文件时如何为每个文件设置 maxUploadSize?

spring - @IntegrationTest 与 @WebIntegrationTest 注释

java - 在 Java 中使用扭曲的子类化构建器模式

java - Spring Security 是基于 JAAS 的吗?

java - 如何在 Android 上获取电子邮件?

java - MySQL 上的@GeneratedValue 多态抽象父类(super class)

java - 混合连接和单表继承以及查询所有对象

java - 使用 spring Data JPA 将 sql 查询的结果映射到 pojo

java - 为什么SpringApplication通过配置加载ApplicationContextInitializer?

java - 通过 log4j 发送 JNI C stderr/stdout