7

org.springframework.scheduling.commonj.WorkManagerTaskExecutor 我有一个使用Spring 创建并在 Websphere Application Server 8 中运行的长时间运行的线程。

问题是即使应用程序已停止,该线程仍会继续运行。该线程也需要停止,但没有发生。我什至试图用它 Thread.currentThread().isInterrupted()来检查当前线程是否被中断但它总是返回false。因此,无法通过我的代码知道线程是否应该继续运行或停止。

这是我对 WorkManagerTaskExecutor 的 spring 配置:

<bean id="taskExecutor" class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
      <property name="workManagerName" value="wm/default" />
</bean>

线程是这样执行的:

Thread t = new EmailReaderThread(email);
workManagerTaskExecutor.execute(t);
  • 我错过了什么?
  • 我该怎么做才能在应用程序停止时应用程序的线程(由应用程序生成的线程)也停止?

我认为这不被视为非托管线程,因为我正在使用适当的WorkManager注册线程,容器将其作为 JNDI 公开的资源。

更新:这是创建线程的代码。

@Service
@Transactional
public class SmsServiceHypermedia implements SmsService {

    @Autowired
    private WorkManagerTaskExecutor workManagerTaskExecutor;


    public SmsServiceHypermedia() {
        createEmailReaderThread();
    }

    private void createEmailReaderThread() {
        log.debug("Generating Email Reader Threads...");
        Email email = getDefaultEmail(); //obtain the default Email object, not important for the problem.
        EmailReaderThread r = new EmailReaderThread(email);
        workManagerTaskExecutor.execute(r);     
    }

    private class EmailReaderThread extends Thread {

        private Email email;
        private Session session;

        public EmailReaderThread(Email email) {
            this.email = email;
        }

        @Override
        public void run()  {
            readEmails();
        }

        public void readEmails() {
            final long delay = 30 * 1000; //delay between message poll.
            log.debug("Starting to read emails for email: " + email.getAddress());
            while(!Thread.currentThread().isInterrupted()) {
                try {
                    log.debug("Current session: " + session);
                    Store store = session.getStore();
                    log.debug("Connecting using session: " + session);
                    store.connect();
                    Folder inbox = store.getFolder("INBOX");
                    inbox.open(Folder.READ_WRITE);

                    javax.mail.Message[] messages = inbox.search(
                            new FlagTerm(new Flags(Flags.Flag.SEEN), false));
                    for (javax.mail.Message message : messages) {
                        //Do something with the message
                    }
                    inbox.close(true);
                    store.close();
                    block(delay);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }

        //I know this could be implemented by calling Thread.sleep() is just that I ran out of options so I also tried it this way.
        private void block(long millis) {
            final long endTime = System.currentTimeMillis() + millis;
            log.debug("Blocking for this amount of time: " + millis + " ms");
            while (System.currentTimeMillis() < endTime) {
            }
            log.debug("End of blocking.");
        }
    }   
}
4

1 回答 1

6

根据 CommonJ 规范,只有当其 isDaemon() 方法返回 true 时,WorkManager 才会尝试停止 Work 的执行。非守护进程预计运行时间较短,因此不需要停止。

问题是,默认情况下,Spring 使用的 Work 实现的 isDaemon() 方法(实际上包装了 Runnable)返回 false。你可以通过让你的 Runnable 实现 SchedulingAwareRunnable 来改变它。

然而,这还不够。如果 WorkManager 决定停止 Work,那么它将调用 Work#release() 并且 Work 本身有责任确保它停止。特别是,WorkManager 不会尝试中断正在执行 Work 的线程(因为这不是停止线程的可靠方法)。问题是 Spring 使用的 Work 实现对 release() 方法有一个空实现,因此您不能使用该功能。

总结一下:如果你想使用 Spring,确保执行停止的唯一方法是为此设计自己的机制。

请注意,使用 SchedulingAwareRunnable 仍然很有趣,因为这将避免 WebSphere 的线程监视器(关于挂起线程)生成的警告。

于 2011-12-29T19:59:23.880 回答