2014-11-24 45 views
0

我有一个Singleton会话Bean执行的后台任务:EJB 3.1的Singleton会话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规范禁止管理自己的线程。你可以做到这一点,但你应该意识到你违反了规范并理解了所有的内在含义。相反,您应该考虑利用Managed Executor服务[1]。

这就是说我怀疑在这里发生的事情是你的taskLoop锁定访问你的单身(包括预销毁)的其他方法。默认情况下@Singleton的所有方法都是@Lock LockType.Write。既然你已经手动同步,你应该尝试用标注@Lock(LockType.Read)你@Singleton类[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'不可用。任何想法?顺便说一下,因为我一直在进行Bean Managed Concurrency,所以@Lock在这里没有必要。 – 2014-11-25 02:17:31

+0

我的问题的最终解决方案是升级到Java EE 7,并使用**单线程**'ExecutorService'和'ManagedThreadFactory'。 @NBW的建议让我在那里,并将其标记为公认的答案。 – 2014-11-25 07:09:31

相关问题