2012-12-18 32 views
23

Tôi có một ứng dụng java độc lập mà sử dụng ExecutorService để xử lý một số công việc song songJboss Java EE container và một ExecutorService

ExecutorService es = Executors.newFixedThreadPool(10); 

bây giờ tôi muốn tái sử dụng cùng một giải pháp trong một đậu EJB nhưng không chắc chắn làm thế nào để khởi tạo chính xác ThreadPool, vì tôi thường rời khỏi thùng chứa Java EE để kiểm soát tất cả các tài nguyên luồng. Tôi có thể chỉ sử dụng cùng một mã hoặc là có một cách chính xác thay thế để có được một hồ bơi thread quản lý Jboss?

Trả lời

25

Cảnh báo bắt buộc: Tạo chủ đề của riêng bạn trong máy chủ ứng dụng Java EE (thậm chí Tomcat) không được khuyến khích vì nó có thể là vấn đề hiệu suất lớn và trong hầu hết các trường hợp sẽ ngăn chức năng vùng chứa, chẳng hạn như JNDI. Các chủ đề mới sẽ không biết ứng dụng nào thuộc về chúng, bộ nạp lớp bối cảnh Thread sẽ không được thiết lập và nhiều vấn đề ẩn khác.

May mắn là có một cách để máy chủ Java EE quản lý nhóm luồng thông qua Java EE 6 @Asynchronous và mẫu thiết kế thông minh này. Di động đến bất kỳ máy chủ được chứng nhận Java EE 6 nào.

Tạo EJB này trong ứng dụng của bạn.

Sau đó, bạn có thể tham khảo bean này ở nơi khác trong ứng dụng của bạn thông qua tiêm phụ thuộc đơn giản (

@EJB 
private Executor executor; 

Sau đó, sử dụng Executor như bình thường.

Nếu các thành phần không phải là một thành phần Java EE, bạn có thể tra cứu đậu qua:

InitialContext initialContext = new InitialContext(); 
Executor executor = (Executor) initialContext.lookup("java:module/Executor"); 
+2

Hơi O/T: Đây là một mô hình rất tốt (chúng tôi sử dụng nó rất nhiều), tuy nhiên nó thiếu ngắn khi thuật toán của bạn yêu cầu các hồ bơi riêng biệt để ngăn chặn deadlocks (xem EJB Spec vấn đề thảo luận về điều này) –

+0

Chúng tôi sử dụng cùng một thiết kế trong ứng dụng của chúng tôi nhưng gần đây chúng tôi đang phải đối mặt với rất nhiều dữ liệu ghi đè trong cơ sở dữ liệu khi chúng tôi đang chạy hành động hàng loạt trong nền bằng cách sử dụng các nhà thực thi. Bất kỳ ý tưởng nào nếu đó có thể là một vấn đề phổ biến/đã biết. Nếu có, sau đó có thể có một sửa chữa có sẵn – Adhir

+0

Cách chính xác để làm điều này là sử dụng một ManagedExecutorService, câu trả lời của tôi [dưới đây] (http://stackoverflow.com/questions/13932083/jboss-java-ee-container-and- a-executorservice/19404609 # 19404609) –

5

Vâng ... giải pháp của David đã không làm việc cho tôi vì những lý do sau đây:

  1. Trình biên dịch đã bitching xung quanh rằng java.util.concurrent không được phép ... mà kinda có ý nghĩa trong phạm vi JBOSS.
  2. Ngoài ra: public STATIC class ...? Đọc lên: Why are you not able to declare a class as static in Java?

Dưới đây là những gì tôi đã làm:
cài đặt của tôi:
- JBoss AS 7.1.1
- Java 1.6
- RHEL
- Chạy ví dụ với GradleArquillian:

@Stateless 
public class ExecutorBean { 
    @Asynchronous 
    public void execute(Runnable command) { 
     command.run();  
    } 
} 

Sau đó, khách hàng của bạn sẽ trông như sau:

@EJB ExecutorBean eb; 
@Test 
public void testExecutorBean() { 
    eb.execute(new YourCustomizedRunnableWhichDoesALotOfUsefulStuff()); 
    assertFalse(!true); 
} 

Hãy cẩn thận, mặc dù: Trong tệp standalone.xml của tôi (hoặc nói chung tệp cấu hình của tôi cho JBOSS tôi có một phần 'thread-pools'. Có một cái nhìn vào nó (nếu bạn xảy ra để sử dụng JBOSSAS) và tinker với các giá trị ở đó. Tìm hiểu cách hoạt động của nó. Khi tôi sử dụng các đề tài với các xét nghiệm arquillian, tôi nhận được các chủ đề bị giết mặc dù thời gian sống của tôi rất cao. Tôi nghĩ rằng điều này đã làm với cách vi sinh vật arquillian. Khi arquillian kết thúc tất cả các chủ đề không hoàn thành bị giết mà đang chạy trong khi các thử nghiệm đang được chạy ...ít nhất đó là những gì tôi nghĩ rằng tôi quan sát. Mặt khác tất cả các chủ đề hoàn thành thực sự cư xử tốt theo nghĩa đó là họ đã hoàn thành nhiệm vụ/hoạt động của mình.

Hy vọng bài đăng này sẽ hữu ích!

+0

Tôi vừa phát minh ra giải pháp thanh lịch nhất cho testmethod của mình: Chỉ cần để chủ đề thử nghiệm chính ngủ một thời gian để các luồng khác nằm dưới sự quản lý của máy chủ ứng dụng có thời gian để hoàn thành. OK ... không thanh lịch, nhưng làm việc. – easyDaMan

+1

Yanked 'static' - mã mà tôi đã sao chép từ là một lớp bên trong tĩnh. Đã xóa vì mã được dán được dự định là lớp cấp cao nhất. –

26

Cách chính xác để thực hiện việc này trong EJB của bạn là sử dụng ManagedExecutorService, một phần của API Uturrency Concurrency (Java EE7). Bạn không nên sử dụng bất kỳ ExecutorService nào là một phần của java.util.concurrent trong mã doanh nghiệp của bạn.

Bằng cách sử dụng ManagedExecutorService, chuỗi mới của bạn sẽ được tạo và quản lý bởi vùng chứa.

Ví dụ sau được lấy từ trang web của tôi here.

Để tạo một chuỗi mới bằng ManagedExecutorService, trước tiên hãy tạo đối tượng nhiệm vụ triển khai Thực hiện cuộc gọi. Trong phương thức call() chúng ta sẽ định nghĩa công việc mà chúng ta muốn thực hiện trong một thread riêng biệt.

public class ReportTask implements Callable<Report> { 

    Logger logger = Logger.getLogger(getClass().getSimpleName()); 

    public Report call() { 
     try { 
      Thread.sleep(3000); 
     catch (InterruptedException e) { 
      logger.log(Level.SEVERE, "Thread interrupted", e); 
     } 
     return new Report(); 
    } 
} 

Sau đó, chúng ta cần phải gọi nhiệm vụ bằng cách đi qua nó mặc dù phương pháp nộp() của ManagedExecutorService.

@Stateless 
public class ReportBean { 

    @Resource 
    private ManagedExecutorService executorService; 

    public void runReports() { 
     ReportTask reportTask = new ReportTask(); 
     Future<Report> future = executorService.submit(reportTask); 
    } 
} 
+5

Đó là cách ưu tiên trong EE 7, nhưng còn EE 6 thì sao? – Vlad

+0

Không có cách nào an toàn để làm điều này là Java EE6. Tôi đoán đây là lý do tại sao nó giành được phiếu bầu được bao gồm trong Java EE7. –

+0

Cảm ơn ... Bằng cách sử dụng Quản lý viên Executor chắc chắn là con đường để đi. – Houston

2

Trước EE7, bạn có thể muốn sử dụng WorkManager từ JSR 237

http://docs.oracle.com/javaee/1.4/api/javax/resource/spi/work/WorkManager.html

đặc tả này hiện đang bị thu hồi, vẫn còn một số máy chủ ứng dụng thực hiện nó. Tôi sử dụng triển khai thực hiện ibm trong WebSphere 8.5 - IBM WorkManager. Đó là tài nguyên được quản lý hoàn toàn, có sẵn trong bảng điều khiển quản trị. Xin lưu ý rằng nó không tương thích với giao diện với Oracle.

Dưới đây là một ví dụ cho phiên bản IBM:

@Resource(lookup = "wm/default") 
WorkManager workManager; 

public void process() { 
    try { 
     ArrayList<WorkItem> workItems = new ArrayList<WorkItem>(); 
     for (int i = 0; i < 100; i++) { 
      // submit 100 jobs 
      workItems.add(workManager.startWork(new Work() { 
       @Override 
       public void run() { 
        try { 
         System.out.println(Thread.currentThread().getName() + " Running"); 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 

       @Override 
       public void release() { 
        System.out.println(Thread.currentThread().getName() + " Released"); 
       } 
      })); 
     } 
     // wait for all jobs to be done. 
     workManager.join(workItems, WorkManager.JOIN_AND, 100000); 
    } catch (WorkException e) { 
     e.printStackTrace(); 
    } 
} 

Ngoài ra tôi biết Commonj Workmanager.

0

Nếu bạn đang sử dụng JBoss, bạn có thể sử dụng org.jboss.seam.async.ThreadPoolDispatcher.

ThreadPoolDispatcher hoàn toàn được quản lý.

Đối với các lớp được quản lý hữu ích khác, hãy xem gói: org.jboss.seam.async.

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