2011-01-14 34 views
36

Tôi có một chuỗi tải xuống dữ liệu và tôi muốn đợi cho đến khi quá trình tải xuống hoàn tất trước khi tôi tải dữ liệu. Có cách nào tiêu chuẩn để làm điều này?Java Đợi thread hoàn thành

Thông tin khác:

Tôi có một lớp Tải xuống nhận dữ liệu từ URL (POJO được tuần tự hóa). Tải xuống là Runnable và Observable. Nó theo dõi các byte tải về và tải về kích thước. Tôi có một thanh tiến trình hiển thị tiến trình cho Người dùng. GUI quan sát Tải xuống để cập nhật thanh tiến trình.

Khi POJO được tải xuống, tôi muốn tải xuống và chuyển sang bước tiếp theo. Mỗi bước phải chờ cho đến khi kết thúc trước. Vấn đề là tôi không thể nghĩ ra một cách để tạm dừng ứng dụng của tôi để chờ chuỗi tải xuống. Sau khi tải xong, tôi muốn gọi download.getObject() sẽ trả về dữ liệu dưới dạng đối tượng. Sau đó tôi có thể truyền và tiếp tục với bản tải xuống tiếp theo.

Tôi có một lớp trợ giúp quản lý URL để tải xuống và thực hiện tất cả các cuộc gọi để Tải xuống. Cuộc gọi này sẽ gọi getObject và thực hiện quá trình truyền. Gui gọi helper.getUser(). helper bắt đầu thread chạy và tôi muốn nó 'biết' khi nó được hoàn thành để nó có thể trả về đối tượng được đúc.

Bất kỳ đề xuất/ví dụ nào? Tôi đang ở giai đoạn đầu của thiết kế này vì vậy tôi sẵn sàng thay đổi nó.

Cảm ơn bạn.

Cập nhật:

Tôi đi theo http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html#get và sử dụng phương thức để chặn cho đến khi thread kết thúc. Mã rất lộn xộn và tôi không thích cách tiếp cận này. Tôi sẽ tiếp tục cố gắng tìm một cách 'sạch' để xử lý quy trình tải xuống.

Trả lời

51

Thread có phương pháp thực hiện điều đó cho bạn. join sẽ chặn cho đến khi chuỗi đã hoàn thành việc thực thi.

+0

tôi đã cố gắng tham gia() nhưng mà giữ GUI từ cập nhật. Lý do tôi sử dụng Thread là giữ cho gui cập nhật trong khi quá trình tải xuống diễn ra. Cuộc gọi tham gia ngăn chặn điều đó xảy ra. – Allan

+4

tham gia() sẽ hoạt động. nếu GUI ngừng cập nhật, bạn có thể phải chi tiết hơn về những chủ đề bạn đang tham gia. Tôi sẽ không tham gia EDT. – akf

+2

Sau đó, bạn cần đảm bảo rằng bạn không gọi 'join()' trong chuỗi xoay. Bạn có thể thực hiện việc này bằng cách tạo một chuỗi phụ trách chuỗi tải xuống của bạn. Đây là bản chất chỉ là một nhân viên nền mà bạn có thể quên đi. Đây là luồng công nhân biết khi nào quá trình tải xuống hoàn tất và phải làm gì tại thời điểm đó. Bạn chỉ cần đảm bảo chỉnh sửa đối tượng xoay được thực hiện trong chủ đề xoay. – unholysampler

3

Nói chung, khi bạn muốn kết thúc chuỗi, bạn nên gọi join() trên đó.

4

Tôi tưởng tượng bạn đang gọi bản tải xuống của mình trong chuỗi nền như được cung cấp bởi một SwingWorker. Nếu vậy, sau đó chỉ cần gọi mã tiếp theo của bạn tuần tự trong cùng phương thức doInBackground của SwingWorker.

10

SwingWorkerdoInBackground() mà bạn có thể sử dụng để tạo thành một tác vụ. Bạn có tùy chọn để tạo phôi get() và đợi tải xuống hoàn tất hoặc bạn có thể ghi đè phương thức done() sẽ được tạo sẵn trên chuỗi gửi sự kiện khi Swingworker hoàn tất.

Swingworker có lợi thế cho cách tiếp cận hiện tại của bạn ở chỗ nó có nhiều tính năng bạn đang tìm kiếm nên không cần phải tái tạo lại bánh xe. Bạn có thể sử dụng các phương pháp getProgress() & setProgress() làm phương án thay thế cho người quan sát trên chương trình chạy để tải xuống. Phương pháp done() như tôi đã nói ở trên được gọi sau khi nhân viên kết thúc thực hiện và được tạo sẵn trên EDT, điều này cho phép bạn tải dữ liệu sau khi quá trình tải xuống hoàn tất.

+2

+1 cho 'SwingWorker'. – trashgod

1

Bất kỳ đề xuất/ví dụ nào? Tôi theo sau SwingWorker ... Mã rất lộn xộn và tôi không thích cách tiếp cận này.

Thay vì get(), mà chờ đợi để hoàn thành, sử dụng process()setProgress() để hiển thị kết quả trung gian, như đề nghị trong đơn giản example này hoặc liên quan example này.

36

Bạn có thể sử dụng CountDownLatch từ gói java.util.concurrent. Nó rất hữu ích khi chờ đợi một hoặc nhiều luồng để hoàn thành trước khi tiếp tục thực hiện trong chuỗi đang chờ.

Ví dụ, chờ đợi ba nhiệm vụ để hoàn thành:

CountDownLatch latch = new CountDownLatch(3); 
... 
latch.await(); // Wait for countdown 

Các chủ đề khác (s) sau đó mỗi cuộc gọi latch.countDown() khi hoàn thành với nhiệm vụ của mình. Khi đếm ngược hoàn tất, ba trong ví dụ này, việc thực thi sẽ tiếp tục.

+0

Vấn đề tương tự như @Alzoid. GUI Thread ngừng hoạt động. –

+0

Hoạt động hoàn hảo cho các ứng dụng không có GUI. – JRichardsz

0

Phương thức join() cho phép một luồng đợi để hoàn thành một cách khác. Tuy nhiên, khi ngủ, tham gia phụ thuộc vào hệ điều hành thời gian, vì vậy bạn không nên giả định rằng tham gia sẽ chờ chính xác miễn là bạn chỉ định.

1

Lựa chọn thay thế tốt hơn cho phương pháp join() đã được phát triển trong một khoảng thời gian.

ExecutorService.html#invokeAll là một giải pháp thay thế.

Thực hiện các tác vụ đã cho, trả về danh sách tương lai giữ trạng thái và kết quả khi hoàn tất. Future.isDone() là đúng cho mỗi phần tử của danh sách được trả về.

Lưu ý rằng tác vụ đã hoàn thành có thể chấm dứt bình thường hoặc bằng cách ném ngoại lệ. Kết quả của phương pháp này không xác định nếu bộ sưu tập đã cho được sửa đổi trong khi thao tác này đang được tiến hành.

ForkJoinPool hoặc Executors.html#newWorkStealingPool cung cấp các giải pháp thay thế khác để đạt được mục đích tương tự.

Ví dụ đoạn mã:

import java.util.concurrent.*; 

import java.util.*; 

public class InvokeAllDemo{ 
    public InvokeAllDemo(){ 
     System.out.println("creating service"); 
     ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); 

     List<MyCallable> futureList = new ArrayList<MyCallable>(); 
     for (int i=0; i<10; i++){ 
      MyCallable myCallable = new MyCallable((long)i); 
      futureList.add(myCallable); 
     } 
     System.out.println("Start"); 
     try{ 
      List<Future<Long>> futures = service.invokeAll(futureList); 
     }catch(Exception err){ 
      err.printStackTrace(); 
     } 
     System.out.println("Completed"); 
     service.shutdown(); 
    } 
    public static void main(String args[]){ 
     InvokeAllDemo demo = new InvokeAllDemo(); 
    } 
    class MyCallable implements Callable<Long>{ 
     Long id = 0L; 
     public MyCallable(Long val){ 
      this.id = val; 
     } 
     public Long call(){ 
      // Add your business logic 
      return id; 
     } 
    } 
} 
0

Bạn có thể sử dụng join() chờ đợi để kết thúc tất cả các chủ đề. Giữ tất cả các đối tượng của chuỗi trong mảng toàn cục tại thời điểm tạo chuỗi. Sau đó giữ nó trong vòng lặp như dưới đây:

for (int i = 0; i < 10; i++) 
{ 
    Thread T1 = new Thread(new ThreadTest(i));     
    T1.start();     
    arrThreads.add(T1); 
} 

for (int i = 0; i < arrThreads.size(); i++) 
{ 
    arrThreads.get(i).join(); 
} 

Kiểm tra ở đây để biết chi tiết hoàn chỉnh: http://www.letmeknows.com/2017/04/24/wait-for-threads-to-finish-java

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