2011-12-28 26 views
7

Tôi có một thread chạy dài mà được tạo ra sử dụng org.springframework.scheduling.commonj.WorkManagerTaskExecutor với mùa xuân và đang chạy trong Websphere Application Server 8.Chủ đề tiếp tục chạy ngay cả sau khi ứng dụng đã được dừng lại ở Websphere

Vấn đề là chủ đề này tiếp tục chạy ngay cả nếu ứng dụng đã bị dừng. Chủ đề đó cần được dừng lại nhưng nó không xảy ra. Tôi thậm chí đã cố gắng sử dụng Thread.currentThread().isInterrupted() để kiểm tra xem chuỗi hiện tại có bị gián đoạn hay không nhưng nó luôn trả về false. Vì vậy, không có cách nào để biết thông qua mã của tôi nếu Chủ đề nên tiếp tục chạy hoặc dừng lại.

Đây là cấu hình mùa xuân của tôi cho WorkManagerTaskExecutor:

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

Các chủ đề đang được thực hiện theo cách này:

Thread t = new EmailReaderThread(email); 
workManagerTaskExecutor.execute(t); 
  • tôi thiếu gì?
  • Tôi có thể làm gì để bất cứ khi nào ứng dụng bị dừng, luồng của ứng dụng (các chủ đề được tạo ra bởi ứng dụng) cũng dừng lại?

Tôi nghĩ rằng đây không được coi là một chuỗi không được quản lý vì tôi đang đăng ký chủ đề bằng cách sử dụng WorkManager thích hợp mà vùng chứa hiển thị dưới dạng tài nguyên bởi JNDI.

Cập nhật: Đây là mã tạo chủ đề.

@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."); 
     } 
    } 
} 
+0

Bạn không nên chuyển Runnable sang WorkManagerTaskExecutor.execute (tác vụ WorkManagerTaskExecutor) thay vì một Thread? – Hyangelo

+0

Một chủ đề thực hiện Runnable như vậy là một Runnable. Tôi nghĩ đó không phải là vấn đề. –

+0

các nhà thực thi không bao giờ gọi phương thức 'start()' của một chuỗi được truyền vào (chỉ có 'run()') để bạn có thể sử dụng một runnable bình thường (không phải là một luồng) –

Trả lời

6

Theo thông số CommonJ, WorkManager sẽ cố gắng ngừng thực thi Công việc nếu phương thức isDaemon() trả về true. Non daemon Works được dự kiến ​​sẽ chạy ngắn để chúng không cần phải dừng lại.

Vấn đề là theo mặc định, phương thức isDaemon() của triển khai Work được Spring sử dụng (và thực sự kết thúc tốt đẹp Runnable) trả về false. Bạn có thể thay đổi điều đó bằng cách thực hiện Runnable implement SchedulingAwareRunnable của bạn.

Tuy nhiên, điều đó là không đủ. Nếu WorkManager quyết định dừng Work, thì nó sẽ gọi Work # release() và nó là trách nhiệm của bản thân Work để đảm bảo rằng nó dừng lại. Đặc biệt, WorkManager sẽ không cố gắng làm gián đoạn luồng đang thực hiện Công việc (vì đó không phải là cách đáng tin cậy để ngăn chặn một luồng). Vấn đề là việc thực hiện công việc được sử dụng bởi Spring có một thực hiện trống cho phương thức release(), do đó bạn không thể sử dụng tính năng đó.

Để tóm tắt: nếu bạn muốn sử dụng Spring, cách duy nhất để đảm bảo rằng việc thực thi bị dừng lại là thiết kế cơ chế của riêng bạn cho điều đó.

Lưu ý rằng vẫn còn thú vị khi sử dụng SchedulingAwareRunnable, vì điều này sẽ tránh được các cảnh báo do trình theo dõi luồng của WebSphere tạo ra (về các chủ đề treo).

+0

Tôi đã kiểm tra mã nguồn của WorkManagerTaskExecutor và những gì bạn đã viết có ý nghĩa hoàn hảo. Cảm ơn bạn. Tôi nghĩ rằng nó là rất xấu mà bạn không thể ghi đè lên "phát hành()" với việc thực hiện của riêng bạn. –

Các vấn đề liên quan