7

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 によってリソースとして公開する適切なWorkManagerを使用してスレッドを登録しているため、これはアンマネージド スレッドとは見なされないと思います。

更新: スレッドを作成するコードは次のとおりです。

@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の仕様によると、WorkManagerは、isDaemon()メソッドがtrueを返した場合にのみ、Workの実行を停止しようとします。非デーモンワークは、停止する必要がないように短時間実行されることが期待されます。

問題は、デフォルトで、Springによって使用される(そして実際にRunnableをラップする)Work実装のisDaemon()メソッドがfalseを返すことです。RunnableにSchedulingAwareRunnableを実装させることで、これを変更できます。

しかし、それだけでは十分ではありません。WorkManagerが作業を停止することを決定した場合、Work#release()を呼び出し、作業が停止することを確認するのは作業自体の責任です。特に、WorkManagerは、作業を実行しているスレッドを中断しようとはしません(これは、スレッドを停止するための信頼できる方法ではないためです)。問題は、Springで使用されるWork実装には、release()メソッドの空の実装があるため、その機能を使用できないことです。

要約すると、Springを使用する場合、実行が停止していることを確認する唯一の方法は、そのための独自のメカニズムを設計することです。

SchedulingAwareRunnableを使用することは、WebSphereのスレッドモニターによって生成される警告(スレッドのハングについて)を回避するため、依然として興味深いことに注意してください。

于 2011-12-29T19:59:23.880 に答える