Поток продолжает работать даже после остановки приложения в Websphere - PullRequest
7 голосов
/ 28 декабря 2011

У меня есть долго работающий поток, который создан с использованием 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);
  • Чего мне не хватает?
  • Что можно сделать, чтобы при остановке приложения поток приложения (потоки, созданные приложением) тоже останавливались?

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

1 Ответ

6 голосов
/ 29 декабря 2011

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

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

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

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

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

...