Поток продолжает работать даже после остановки приложения в Websphere

у меня есть длинный поток, который создается с помощью org.springframework.scheduling.commonj.WorkManagerTaskExecutor с Spring и работает в Websphere Application Server 8.

проблема в том, что этот поток продолжает работать, даже если приложение было остановлено. Эту нить тоже нужно остановить, но этого не происходит. Я даже пытался использовать Thread.currentThread().isInterrupted() чтобы проверить, был ли прерван текущий поток, но он всегда возвращает false. Таким образом, нет способа узнать через мой код, должен ли поток продолжать работать или остановка.

это моя весенняя конфигурация для WorkManagerTaskExecutor:

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

поток выполняется таким образом:

Thread t = new EmailReaderThread(email);
workManagerTaskExecutor.execute(t);
  • что я упустил?
  • что я могу сделать, чтобы всякий раз, когда приложение остановлено, поток приложения (потоки, которые были созданы приложением) тоже останавливается?

Я думаю, что это не считается неуправляемым потоком, потому что я регистрирую поток с помощью соответствующий администратора заданий который контейнер предоставляет в качестве ресурса 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.");
        }
    }   
}

1 ответов


согласно спецификациям CommonJ, WorkManager попытается остановить выполнение работы, только если его метод isDaemon() возвращает true. Ожидается, что работы non daemon будут короткими, поэтому их не нужно останавливать.

проблема в том, что по умолчанию метод isDaemon() реализации работы, используемый Spring (и который фактически обертывает Runnable), возвращает false. Вы можете изменить это, сделав свою Runnable реализацию SchedulingAwareRunnable.

однако этого недостаточно. Если WorkManager решит остановить работу, то он вызовет Work#release (), и это ответственность самой работы, чтобы убедиться, что она останавливается. В частности, WorkManager не будет пытаться прервать поток, выполняющий работу (потому что это не надежный способ остановить поток). Проблема в том, что рабочая реализация, используемая Spring, имеет пустую реализацию для метода release (), поэтому что вы не можете использовать эту функцию.

подведем итог: если вы хотите использовать Spring, единственный способ убедиться, что казнь будет остановлена, чтобы создать свой собственный механизм для этого.

обратите внимание, что по-прежнему интересно использовать SchedulingAwareRunnable, поскольку это позволит избежать предупреждений, генерируемых монитором потоков WebSphere (о зависании потоков).