Phương thức Thread.join () trong Java

1. Khái quát chung

Trong hướng dẫn này, chúng ta sẽ thảo luận về các phương thức join () khác nhau trong lớp Thread . Chúng ta sẽ đi vào chi tiết của các phương pháp này và một số mã ví dụ.

Giống như các phương thức wait ()thông báo () , join () là một cơ chế đồng bộ hóa liên luồng khác.

Bạn có thể xem nhanh hướng dẫn này để đọc thêm về wait ()thông báo () .

2. Phương thức Thread.join ()

Phương thức nối được định nghĩa trong lớp Thread :

public final void join () ném InterruptException

Chờ cho chủ đề này chết.

Khi chúng ta gọi phương thức join () trên một luồng, luồng đang gọi sẽ chuyển sang trạng thái chờ. Nó vẫn ở trạng thái chờ cho đến khi kết thúc luồng được tham chiếu.

Chúng ta có thể thấy hành vi này trong đoạn mã sau:

class SampleThread extends Thread { public int processingCount = 0; SampleThread(int processingCount) { this.processingCount = processingCount; LOGGER.info("Thread Created"); } @Override public void run() { LOGGER.info("Thread " + this.getName() + " started"); while (processingCount > 0) { try { Thread.sleep(1000); } catch (InterruptedException e) { LOGGER.info("Thread " + this.getName() + " interrupted"); } processingCount--; } LOGGER.info("Thread " + this.getName() + " exiting"); } } @Test public void givenStartedThread_whenJoinCalled_waitsTillCompletion() throws InterruptedException { Thread t2 = new SampleThread(1); t2.start(); LOGGER.info("Invoking join"); t2.join(); LOGGER.info("Returned from join"); assertFalse(t2.isAlive()); } 

Chúng ta sẽ mong đợi kết quả tương tự như sau khi thực thi mã:

INFO: Thread Created INFO: Invoking join INFO: Thread Thread-1 started INFO: Thread Thread-1 exiting INFO: Returned from join

Phương thức join () cũng có thể trả về nếu luồng được tham chiếu bị gián đoạn . Trong trường hợp này, phương thức ném ra một ngoại lệ bị gián đoạn .

Cuối cùng, nếu luồng được tham chiếu đã bị kết thúc hoặc chưa được bắt đầu, thì phương thức call to join () sẽ trả về ngay lập tức .

Thread t1 = new SampleThread(0); t1.join(); //returns immediately

3. Phương thức Thread.join () với Timeout

Phương thức join () sẽ tiếp tục chờ nếu luồng được tham chiếu bị chặn hoặc quá lâu để xử lý. Điều này có thể trở thành một vấn đề vì chuỗi gọi sẽ trở nên không phản hồi. Để xử lý những tình huống này, chúng tôi sử dụng các phiên bản quá tải của phương thức join () cho phép chúng tôi chỉ định khoảng thời gian chờ.

Có hai phiên bản định thời làm quá tải phương thức join () :

“Public final void join (long millis ) ném InterruptException

Chờ đợi nhiều nhất là millis mili giây cho chủ đề này đến chết. Thời gian chờ bằng 0 có nghĩa là phải chờ đợi mãi mãi ”.

“Public Final void join (long millis, intnanos ) ném InterruptException

Chờ đợi nhiều nhất là millis mili giây cộng nanos nano giây cho chủ đề này đến chết.”

Chúng ta có thể sử dụng tham gia hẹn giờ () như sau:

@Test public void givenStartedThread_whenTimedJoinCalled_waitsUntilTimedout() throws InterruptedException { Thread t3 = new SampleThread(10); t3.start(); t3.join(1000); assertTrue(t3.isAlive()); } 

Trong trường hợp này, luồng đang gọi đợi khoảng 1 giây để luồng t3 kết thúc. Nếu luồng t3 không kết thúc trong khoảng thời gian này, phương thức join () trả về quyền điều khiển phương thức gọi.

Timed join () phụ thuộc vào hệ điều hành để định thời gian. Vì vậy, chúng ta không thể giả định rằng join () sẽ đợi chính xác lâu như đã chỉ định.

4. Phương thức và đồng bộ hóa Thread.join ()

Ngoài việc đợi cho đến khi kết thúc, việc gọi phương thức join () có tác dụng đồng bộ hóa. join () tạo mối quan hệ xảy ra trước:

“Tất cả các hành động trong một chuỗi xảy ra trước khi bất kỳ chuỗi nào khác trả về thành công từ một tham gia () trên chuỗi đó.”

Điều này có nghĩa là khi một luồng t1 gọi t2.join (), thì tất cả các thay đổi được thực hiện bởi t2 sẽ hiển thị trong t1 khi trả về. Tuy nhiên, nếu chúng tôi không gọi tham gia () hoặc sử dụng các cơ chế đồng bộ hóa khác, chúng tôi không có bất kỳ đảm bảo nào rằng các thay đổi trong luồng khác sẽ hiển thị với luồng hiện tại ngay cả khi luồng khác đã hoàn thành.

Do đó, mặc dù lời gọi phương thức join () tới một luồng ở trạng thái kết thúc trả về ngay lập tức, chúng ta vẫn cần gọi nó trong một số trường hợp.

Chúng ta có thể xem một ví dụ về mã được đồng bộ hóa không đúng bên dưới:

SampleThread t4 = new SampleThread(10); t4.start(); // not guaranteed to stop even if t4 finishes. do { } while (t4.processingCount > 0);

Để đồng bộ hóa đúng đoạn mã trên, chúng ta có thể thêm t4.join () định thời vào bên trong vòng lặp hoặc sử dụng một số cơ chế đồng bộ hóa khác.

5. Kết luận

Phương thức join () khá hữu ích để đồng bộ hóa liên luồng. Trong bài viết này, chúng tôi đã thảo luận về các phương thức join () và hành vi của chúng. Chúng tôi cũng đã xem xét mã bằng phương thức join () .

Như mọi khi, mã nguồn đầy đủ có thể được tìm thấy trên GitHub.