Метод длительного бега, вызывающий состояние гонки - PullRequest
0 голосов
/ 27 мая 2010

Я относительно новичок в спящем режиме, поэтому, пожалуйста, будьте осторожны. У меня проблема с долго работающим методом (~ 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: мой сеанс гибернации управляется весной.

Ответы [ 2 ]

2 голосов
/ 27 мая 2010

Как правило, вам нужно разрешить запускать его в отдельном 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 {
        // ...
    }
}

С Status в 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. При этом вы можете контролировать максимальное количество потоков и указывать время ожидания.

0 голосов
/ 27 мая 2010

Что делает метод doSomethingAndTakeALongTime()? это для работы с БД или просто для выполнения бизнес-логики?

Если он не выполняет никаких операций с БД, и вы получили status нормально, то вы можете сохранить объект перед вызовом этого метода.

И если он выполняет какую-то операцию с БД, вам нужно подождать. Таким образом, даже если вы добавляете поток, вам нужно дождаться его завершения (используя thread.join(), мы можем это сделать)

Дело в том, что перед тем, как упорствовать, вы должны выполнить все операции, основанные на вашем объекте ORM, верно? поэтому постарайтесь оптимизировать логику для метода, чтобы он выполнялся до того, как вы сохранитесь.

спасибо.

...