2013-04-04 38 views
9

Mã hiện tại của tôi sử dụng hàng loạt các quy trình không đồng bộ đạt đến kết quả cao nhất. Tôi cần phải bọc mỗi trong số này theo cách mà mỗi được truy cập bởi một phương pháp đồng bộ với kết quả như là một giá trị trả về. Tôi muốn sử dụng dịch vụ thực thi để thực hiện điều này, để cho phép nhiều dịch vụ này xảy ra cùng một lúc. Tôi có cảm giác rằng Tương lai có thể thích hợp với việc thực hiện của tôi, nhưng tôi không thể tìm ra cách tốt để thực hiện điều này.Gói một loạt các cuộc gọi không đồng bộ với một phương thức đồng bộ với giá trị trả về

Những gì tôi có bây giờ:

public class DoAJob { 
    ResultObject result; 

    public void stepOne() { 
    // Passes self in for a callback 
    otherComponent.doStepOne(this); 
    } 

    // Called back by otherComponent once it has completed doStepOne 
    public void stepTwo(IntermediateData d) { 
    otherComponent.doStepTwo(this, d); 
    } 

    // Called back by otherComponent once it has completed doStepTwo 
    public void stepThree(ResultObject resultFromOtherComponent) { 
    result = resultFromOtherComponent; 
    //Done with process 
    } 
} 

này đã làm việc khá tốt trong nội bộ, nhưng bây giờ tôi cần phải lập bản đồ quy trình của tôi vào một phương pháp đồng bộ với một giá trị trả về như:

public ResultObject getResult(){ 
    // ??? What goes here ??? 
} 

Có ai có một ý tưởng hay về cách thực hiện điều này một cách thanh lịch?

+1

Một điều bị thiếu trong thông số này: làm thế nào để bạn có kế hoạch kết hợp các ResultObject của các nhiệm vụ khác nhau vào một duy nhất ở cuối? –

+0

Tôi không chắc mình có hiểu câu hỏi hay không. Thông thường, quá trình này được khởi động bởi DoAJob.stepOne() mới; phương thức stepTwo() được bắt đầu bằng một cuộc gọi lại từ otherComponent. Ở cuối chuỗi gọi lại, ResultObject được điền chính xác. Bất kỳ bit dữ liệu trung gian nào cũng được tích hợp vào kết quả cuối cùng. – irondwill

Trả lời

0

tôi khuyên bạn nên sử dụng invokeAll(..). Nó sẽ gửi một tập hợp các nhiệm vụ cho người thi hành và chặn cho đến khi người cuối cùng hoàn thành (thành công/với ngoại lệ). Sau đó nó trả về một danh sách các đối tượng tương lai đã hoàn thành, vì vậy bạn có thể lặp lại chúng và kết hợp các kết quả vào một ResultObject đơn lẻ.

Trong bạn muốn chạy chỉ có một nhiệm vụ duy nhất một cách đồng bộ, bạn có thể sử dụng như sau:

executor.invokeAll(Collections.singleton(task)); 

--edit--

Bây giờ tôi nghĩ mình hiểu rõ hơn về nhu cầu của bạn. Tôi cho rằng bạn cần một cách để gửi các chuỗi nhiệm vụ độc lập. Vui lòng xem mã tôi đã đăng trong this answer.

+0

Tôi đã không minh họa điều này tốt trong ví dụ của tôi, nhưng các bước phụ thuộc vào bước trước đó được hoàn thành. Ví dụ, stepTwo() được thực hiện khi hoàn tất từ ​​xa stepOne(). stepTwo() về cơ bản là hoàn thành gọi lại cho thành phần được gọi trong bướcOne() – irondwill

7

Nếu bạn muốn bật một hoạt động không đồng bộ (thực hiện gọi lại khi hoàn tất), thành một đồng bộ/chặn, bạn có thể sử dụng hàng đợi chặn. Bạn có thể quấn nó lên trong một đối tượng tương lai nếu bạn muốn.

  1. Xác định một hàng đợi chặn có sức chứa chỉ là một phần tử:

    BlockingQueue<Result> blockingQueue = new ArrayBlockingQueue<Result>(1);

  2. Bắt đầu quá trình đồng bộ của bạn (sẽ chạy ở chế độ nền), và viết gọi lại như vậy mà khi nó được thực hiện, nó thêm kết quả của nó vào hàng đợi chặn.

  3. Trong thread foreground/ứng dụng của bạn, có mất() khỏi hàng đợi, mà khối cho đến khi một yếu tố trở nên có sẵn:

    Result result = blockingQueue.take();

tôi đã viết một cái gì đó tương tự trước (nhu cầu đề foreground để chặn phản hồi không đồng bộ từ máy từ xa) bằng cách sử dụng một cái gì đó như Tương lai, bạn có thể tìm mã ví dụ here.

+0

Một 'SynchronousQueue' có lẽ tốt hơn cho mục đích này – ZhongYu

+2

Tôi đã ở đó trước khi tôi sợ (với mã tôi liên kết với thực tế). Một SynchronousQueue có thể gây ra các thread nền để chặn hoặc nhận được một ngoại lệ, nếu có một điều kiện chủng tộc sao cho thread nền hoàn thành trước khi các chủ đề tiền cảnh gọi là take(). Nếu điều này được bao bọc trong một tương lai như OP được đề cập, nó có thể là một sự kiện phổ biến nếu ứng dụng thực hiện một số công việc khác trước khi gọi cho Future.get(). – npgall

0

Nếu bạn muốn để có được bàn tay của bạn bẩn, bạn có thể làm điều này

ResultObject result; 

public void stepOne() 

    otherComponent.doStepOne(this); 

    synchronized(this) 
     while(result==null) this.wait(); 
    return result; 

public void stepThree(ResultObject resultFromOtherComponent) 

    result = resultFromOtherComponent; 

    synchronized(this) 
     this.notify(); 

Hoặc bạn có thể sử dụng công cụ mức đồng thời cao hơn, như BlockingQueue, Semaphore, CountdownLatch, Phaser, vv vv

Note rằng DoAJob không phải là chủ đề an toàn - rắc rối đảm bảo nếu hai chủ đề gọi stepOne cùng một lúc.

+0

Vâng tôi có thể sẽ phải làm một cái gì đó như vậy vì nó có vẻ là một trường hợp sử dụng và kiến ​​trúc khá cụ thể. Tôi đã hy vọng tránh phải thực hiện wait() vòng hoặc junking lên mã của tôi với quá nhiều đồng bộ() cuộc gọi. – irondwill

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