导致竞争状态的长时间运行方法
我对休眠比较新,所以请温和。我遇到了长时间运行的方法(〜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。
我已经尝试更新字段并手动刷新会话,但它似乎没有工作。我不知道该从这里做什么,并希望得到任何帮助。
PS:我的hibernate会话是由spring管理的。
基本上你需要让它运行在一个单独的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
代替。因此,您可以控制最大线程数并指定超时。
嗯...我试图让foo()今天早些时候同步,它似乎没有工作。我所做的只是添加“同步”修改器。还有什么你必须做的,使其成为一个同步的方法? – keeleyt83 2010-05-27 03:22:00
“同步”只有在您执行BalusC讨论的其他线程相关工作时才有所帮助。是你做的吗? – 2010-05-27 05:32:13
@keeley:'synchronized'修饰符就是为了避免另一个线程在状态仍然设置为'RUNNING'的情况下进入该方法(因此您可能会冒险执行长时间运行的任务两次或更多)。它不会立即返回该方法。在另一个线程中执行长时间运行的任务将立即返回该方法。你试过了吗? – BalusC 2010-05-27 11:15:53
doSomethingAndTakeALongTime()
正在做什么?是用于数据库操作还是只是执行一些业务逻辑?
如果它没有做任何数据库操作,并且你的status
没有问题,那么你可以在调用该方法前坚持该对象。
如果它做一些数据库操作,那么你需要等待它。因此,即使你把线程,你需要等待该线程完成(使用thread.join()
我们可以做到这一点)
事情是,在你坚持之前,你必须完成所有操作基于你的ORM对象吗?所以请尝试优化该方法的逻辑,使其在执行前保持执行。
谢谢。
为了避免红鲱鱼:你知道你应该使用'equals()'来比较字符串吗? – BalusC 2010-05-26 22:06:25
您的方法是否在交易环境中,例如春季声明式交易?如果是这样,那么冲洗将无法帮助,因为其他用户不会看到更改。 – mdma 2010-05-26 22:09:48
@BalusC,是的,我知道这一点。我的真实代码不使用字符串;我刚刚创建了这个例子,并且不正确,为了您的观看乐趣。 :) – keeleyt83 2010-05-27 02:59:04