2014-11-24 4 views
0

У меня есть Singleton Session Bean исполняющие фоновые задачи:метод EJB 3.1 Singleton Session Bean @PreDestroy не называется

@Singleton 
@ConcurrencyManagement(ConcurrencyManagementType.BEAN) 
@TransactionManagement(TransactionManagementType.BEAN) 
@Startup 
public class TaskQueue { 

private static final Logger LOGGER = Logger.getLogger("TaskQueue"); 

@Resource 
private SessionContext sessionContext; 

private final ArrayList<Runnable> tasks = new ArrayList<Runnable>(); 
private boolean running = false; 

@PostConstruct 
public void postConstruct() { 
    LOGGER.info("postConstruct"); 

    running = true; 
    sessionContext.getBusinessObject(TaskQueue.class).taskLoop(); 
} 

@PreDestroy 
public void preDestroy() { 
    LOGGER.info("preDestroy"); 
    running = false; 
    synchronized (tasks) { 
     tasks.notifyAll(); 
    } 
} 

public void addTask(Runnable r) { 
    synchronized (tasks) { 
     tasks.add(r); 
     tasks.notifyAll(); 
    } 
} 

@Asynchronous 
public void taskLoop() { 
    while (running) { 
     Runnable task; 
     synchronized (tasks) { 
      LOGGER.info("Fetching next task..."); 
      if (tasks.isEmpty()) { 
       try { 
        LOGGER.info("Task queue is empty. Waiting..."); 
        tasks.wait(); 
        LOGGER.info("Resumed"); 
        continue; 
       } catch (InterruptedException e) { 
        break; 
       } 
      } 

      task = tasks.remove(0); 
     } 

     LOGGER.info("Executing task..."); 
     task.run(); 
    } 

    running = false; 
    LOGGER.info("Task queue exited"); 
} 
} 

Когда я попытался остановить модуль, отмените развертывание модуля или остановить сервер, метод preDestroy() не вызывается, а процесс остановки/отказа не будет продолжаться. Единственный способ остановить сервер - убить процесс Java.

Я использую Jboss EAP 6.0.

Что случилось с моим кодом? Как это исправить, или какой альтернативный способ обработки фоновой задачи с помощью EJB 3.1?

ответ

1

Во-первых, управление своими потоками запрещено спецификацией EE. Вы можете это сделать, но вам следует знать, что вы нарушаете спецификацию и понимаете все присущие им последствия. Вместо этого вы должны изучить возможность использования службы Управляемого Исполнителя [1].

С учетом сказанного, что я подозреваю, здесь происходит то, что ваш taskLoop блокирует доступ к остальным вашим методам Singletons (включая pre-destroy). По умолчанию все методы в @Singleton - @Lock LockType.Write. Так как ваш уже вручную синхронизации вы должны попробовать аннотирования свой класс @Singleton с @Lock (LockType.Read) [2]

[1] https://docs.oracle.com/javaee/7/api/javax/enterprise/concurrent/ManagedExecutorService.html

[2] https://docs.oracle.com/javaee/6/api/javax/ejb/LockType.html

+0

К сожалению, я работаю с Java EE ** 6 **, в котором 'ManagedExecutorService' недоступен. Есть идеи? Кстати, @Lock здесь не нужен, так как я занимаюсь Bean Managed Concurrency. –

+0

Окончательное решение моей проблемы - переход на Java EE 7 и использование ** однопоточного ** 'ExecutorService' с' ManagedThreadFactory'. Предложение @NBW привело меня туда, и я обозначил его как принятый ответ. –

Смежные вопросы