长跑方法导致竞争条件

时间:2010-05-26 22:03:51

标签: java hibernate spring race-condition

我对休眠比较新,所以请保持温和。我遇到了长时间运行的方法(约2分钟长)和更改存储在DB中的对象的状态字段值的问题。下面的伪代码应该有助于解释我的问题。

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(),但前提是它的状态为“ready”。每当doSomethingAndTakeALongTime()花费2分钟完成并且对事物的状态字段的更改没有持久到数据库直到它离开foo()时,我的问题就出现了。因此,另一个用户可以在这2分钟内提出请求,if语句将评估为true。

我已经尝试更新字段并手动刷新会话,但似乎没有用。我不知道该怎么做,并希望得到任何帮助。

PS:我的hibernate会话由spring管理。

2 个答案:

答案 0 :(得分:2)

基本上你需要让它在一个单独的Thread中运行,以使方法立即返回。否则它将确实阻塞,直到长时间运行的任务完成。您可以将实体本身传递给线程,以便它可以更新状态本身。这是使用简单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中的Status,您甚至可以使用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。因此,您可以控制最大线程数并指定超时。

答案 1 :(得分:0)

方法doSomethingAndTakeALongTime()正在做什么?它是用于DB操作还是仅执行一些业务逻辑?

如果它没有进行任何数据库操作,并且你的status没有问题,那么你可以在调用该方法之前保留该对象。

如果它做了一些DB操作,那么你需要等待它。所以,即使你输入了线程,你也需要等待该线程完成(使用thread.join()我们可以这样做)

事实是,在你坚持之前你必须完成基于你ORM对象的所有操作吗?所以尝试优化方法的逻辑,以便在持久化之前执行它。

感谢。