Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> 2 потока вытягивают из БД одну и ту же задачу 
:(
    Опции темы
barracuda477
Дата 1.5.2009, 21:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 14.12.2008

Репутация: нет
Всего: нет



Есть несколько потоков, они вытягивают из БД (через Hibernate) по одной задачке (через fetchAndLockTopPriorityTask) и обрабатывают каждую задачу .
Выполнение каждой задачи занимает от 1 до 10 секунд.

Код метода fetchAndLockTopPriorityTask() приведён ниже и делает следующее:
1) находит 1 топ-задачу со статусом "новая задача"
2) изменяет статус этой задачи в "задача в обработке" (чтобы задача не могла быть вытянута другим потоком)

Метод fetchAndLockTopPriorityTask() реализован в инстансе фабрики TaskBOF. 
Каждому потоку при конструировании передан один и тот же инстанс этой фабрики.

Проблема в том, что иногда (воспроизводимо в течении 50-200 секунд) 2 потока вытягивают из БД одну и ту же задачу.

Код

....

public class TaskBOF extends TaskGenBOF {

.....

  /**
   * Reruns next task for processing (picks up with highest priority)
   * @return Task or null if no task for processing available
   */
  public synchronized Task fetchAndLockTopPriorityTask() {
    Session session = getSessionFactory().openSession();
    Criteria criteria = session.createCriteria(Task.class);
    criteria.add(Restrictions.eq("status", TaskStatus.New.getStatus()));
    criteria.addOrder(Order.desc("priority"));
    criteria.setMaxResults(1);
    List<Task> tasks = criteria.list();
    session.close();
    if (tasks.size() > 0) {
      Task taskForProcessing = tasks.get(0);
      taskForProcessing.setStatus(TaskStatus.Processing.getStatus());
      update(taskForProcessing);
      return taskForProcessing;
    } else {
      return null;
    }
  }

.....

/**
* Updates object into Database
* @param obj
*/
  public void update(Object obj) {
    Session session = getSessionFactory().openSession();
    Transaction transaction = session.beginTransaction();
    session.update(obj);
    transaction.commit();
  } 


Лог вытягивания задач (задачи с одинаковым ИД могут отстоять друг от друга на несколько секунд)

20:52:35,109  INFO QueueProcessorThread:113 - Thread #4:Fetched task:249956;
20:52:37,062  INFO QueueProcessorThread:113 - Thread #2:Fetched task:250212;
20:52:37,546  INFO QueueProcessorThread:113 - Thread #3:Fetched task:250468;
20:52:41,015  INFO QueueProcessorThread:113 - Thread #6:Fetched task:250212;



Это сообщение отредактировал(а) barracuda477 - 1.5.2009, 22:10
PM MAIL   Вверх
NeoNYura
Дата 1.5.2009, 22:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 60
Регистрация: 10.3.2008

Репутация: нет
Всего: нет



А как потоки создаешь?


можно контролировать на уровне БД, а можно на уровне клиента к бд.

1)Если на уровне БД, то в базе можно выставить запрет на одновременный доступ к таблице, пока не закрыл сессию
2)можно на уровне клиента, например доступ бд через синглтон.





PM MAIL   Вверх
barracuda477
Дата 1.5.2009, 23:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 14.12.2008

Репутация: нет
Всего: нет



Потоки делаю вот так:

Код

...

public class QueueProcessor  {
    
 ...

  private TaskBOF taskBof = new TaskBOF();
  private int threads = 6;

    public static void main (String[] parameters) throws Exception {
        QueueProcessor qp = new QueueProcessor();
        qp.startProcessing();
  }

  /**
   * Creating and launches processing threads
   * @throws Exception - any exception type
   */
  private void startProcessing() throws Exception {
    setAllProcessingTasksToNew();
    for (int i = 1; i <= threads; i++) {
      QueueProcessorThread queueProcessorThread = new QueueProcessorThread(i, taskBof, statistics);
      new Thread(queueProcessorThread).start();
    }
  }


Цитата

1)Если на уровне БД, то в базе можно выставить запрет на одновременный доступ к таблице, пока не закрыл сессию
2)можно на уровне клиента, например доступ бд через синглтон.


1) Нет, лочить всю таблицу не хочу, тем более что как видно по логу - задачи с одинаковым ИД могут отстоять друг от друга на несколько секунд.
2) Ну как бы у меня Хиберенейт и синглтон тут выткать не имеет смысла smile 
Кстати, как я указал - запрет на одновременный доступ к методу fetchAndLockTopPriorityTask() реализован через synchronized с блокировкой расшаренной между всеми потоками фабрики.

Думаю на какое-то кеширование в хибренейте, но пробовал по всякому (setCacheMode, setFlushMode) - не помогло


Это сообщение отредактировал(а) barracuda477 - 1.5.2009, 23:07
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0624 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.