Hiểu java.lang.Thread.State: WAITING (đỗ xe)


91

Đầu tiên, một câu hỏi thực sự ngớ ngẩn, tôi chỉ tự hỏi 'bãi đậu xe' đang chờ có nghĩa là gì? Luồng đang chờ được đậu hay nó vừa được đậu và do đó ở trạng thái chờ? Và khi quá trình đỗ xe đó xảy ra, tài nguyên CPU / bộ nhớ được sử dụng là bao nhiêu? Mục đích của việc đậu một chủ đề là gì?

Thứ hai, bằng cách xem xét phương thức park trong API luồng java

Tắt luồng hiện tại cho mục đích lập lịch luồng trừ khi có giấy phép.

Nếu giấy phép có sẵn thì nó sẽ được sử dụng và cuộc gọi trở lại ngay lập tức; nếu không luồng hiện tại sẽ bị vô hiệu hóa cho mục đích lập lịch luồng và nằm im cho đến khi một trong ba điều xảy ra .....

Tiếng Anh không phải là ngôn ngữ chính của tôi, vì vậy tôi gặp một số khó khăn khi hiểu điều đó, tôi dự định 'cho phép' như một loại 'cho phép đỗ chuỗi', vì vậy các câu hỏi sau:

  • ý nghĩa của điều đó là gì, 'giấy phép' là gì, ai và làm cách nào để kiểm tra giấy phép đó?
  • Điều đó có nghĩa là gì: 'nếu giấy phép có sẵn thì nó sẽ được tiêu thụ', nó có bị 'đậu' không?
  • sau đây, nếu điểm thứ hai là đúng, vậy sự khác biệt giữa "đậu xe" và "nằm im" là gì? Nếu tôi có giấy phép, tôi có thể đậu nó mãi mãi và nếu không, tôi có thể làm nó 'không hoạt động'?

Cảm ơn

Câu trả lời:


37

Permit có nghĩa là một sự cho phép để tiếp tục thực thi. Bãi đậu xe có nghĩa là tạm ngừng thực hiện cho đến khi có giấy phép.

Không giống như Semaphorecác giấy phép của, các giấy phép của LockSupportđược liên kết với các luồng (tức là giấy phép được cấp cho một luồng cụ thể) và không tích lũy (nghĩa là chỉ có thể có một giấy phép cho mỗi luồng, khi luồng sử dụng giấy phép, nó sẽ biến mất).

Bạn có thể cấp phép cho một chủ đề bằng cách gọi unpark(). Một luồng có thể tạm ngừng thực thi của nó cho đến khi có giấy phép (hoặc luồng bị gián đoạn hoặc hết thời gian chờ, v.v.) bằng cách gọi park(). Khi có giấy phép, luồng đỗ sẽ sử dụng nó và thoát khỏi một park()phương thức.


2
Vì vậy, giả sử lại, nếu luồng A gọi 'công viên' cho luồng B, nhưng vẫn có giấy phép, là 'B không thể đậu', thì lệnh gọi được thực hiện bởi A chỉ quay lại và B không đậu. Ngược lại, khi không có giấy phép, B phải tuân theo. Vậy, việc chờ (đỗ xe) có nghĩa là "A đang cố đỗ xe cho tôi vì tôi không có giấy phép nhưng tôi không thể làm điều đó ngay bây giờ nên tôi cũng đang chặn A"? Xin lỗi vì câu dài này. Tôi cho rằng việc chờ đợi này khá tốn tài nguyên. Tôi vẫn đang tự hỏi ai là người quản lý toàn bộ giấy phép. Ai / cái gì đang quyết định rằng một số luồng có giấy phép, trong khi những luồng khác thì không.
Leonardo

2
@Leonardo: Một luồng chỉ có thể tự đậu, không có cách nào để đậu các luồng khác. Vì vậy, gọi park()có nghĩa là "Tôi muốn tạm ngừng thực thi của mình cho đến khi một số luồng khác cấp phép cho tôi bằng cách gọi unpark()".
axtavt

Vì vậy, một chủ đề không thể đậu các chủ đề khác, nhưng có thể được bỏ đánh dấu bởi các chủ đề khác? Đúng không ? Vậy, việc đỗ xe đó xảy ra khi nào? Có thể một luồng không có công việc gì để làm vào lúc này, và cách kiểm tra nó là bằng cách liên tục xem xét giấy phép của nó? Điều này sẽ rất phù hợp với luồng daemon chẳng hạn.
Leonardo

Ngoài ra, WAITING (đậu xe) có nghĩa là nó đang chờ được đậu, hay nó ở trạng thái chờ sau khi được đậu? Xin lỗi, tôi biết đây là một câu hỏi ngớ ngẩn :-)
Leonardo

3
@Leonardo: Nó có nghĩa là trạng thái chờ sau khi được đậu.
axtavt

11

Theo Tài liệu trạng thái luồng java , một luồng có thể chuyển sang trạng thái CHỜ vì ba lý do:

  1. Object.wait mà không có thời gian chờ
  2. Thread.join mà không có thời gian chờ
  3. LockSupport.park

Khi bạn gọi một phương thức công viên trên một Luồng, nó sẽ vô hiệu hóa luồng đó cho mục đích lập lịch luồng trừ khi có giấy phép. Bạn có thể gọi phương thức hủy đánh dấu để cung cấp giấy phép cho luồng đã cho, nếu nó chưa có sẵn.

Vì vậy, khi Thread của bạn ở chế độ WAITING bởi LockSupport.park, nó sẽ hiển thị cho bạn là WAITING (đỗ xe).

Xin lưu ý rằng, bạn chỉ có thể gọi park trên Thread hiện tại. Đây là cơ chế rất hữu ích để triển khai Mẫu thiết kế Nhà sản xuất-Người tiêu dùng.


3

Từ mô tả lớp (ở đầu javadoc LockSupport ), nơi nó mô tả giấy phép:

Lớp này liên kết với mỗi luồng sử dụng nó, một giấy phép (theo nghĩa của lớp Semaphore). Một cuộc gọi đến đậu xe sẽ trở lại ngay lập tức nếu giấy phép có sẵn, sử dụng [giấy phép] trong quá trình này; nếu không thì [cuộc gọi đỗ xe] có thể bị chặn. Một cuộc gọi để hủy đánh dấu làm cho giấy phép khả dụng, nếu nó chưa có sẵn. (Không giống như với Semaphores, giấy phép không tích lũy. Chỉ có nhiều nhất một.)

(Tôi đã mở rộng [văn bản] để dễ đọc hơn đối với những người không nói tiếng Anh.)

Hy vọng rằng ai đó có hiểu biết sâu hơn có thể giải thích thêm về điều này. Xem câu trả lời của axtavt.

Như một lưu ý cuối cùng, một trích dẫn cuối cùng từ javadoc:

Các phương pháp này được thiết kế để sử dụng làm công cụ tạo các tiện ích đồng bộ hóa cấp cao hơn và bản thân chúng không hữu ích cho hầu hết các ứng dụng điều khiển đồng thời.


3

Phần khiến tôi phải xem lại câu hỏi này mà tôi không thể hiểu được khi đọc tài liệu, là:

Nếu giấy phép có sẵn thì nó sẽ được sử dụng và cuộc gọi sẽ trở lại ngay lập tức ...

Vì vậy, khi giấy phép "có sẵn", ailàm thế nào để sẵn có để nó có thể được tiêu thụ ngay lập tức? Điều này bằng cách nào đó rất nhỏ để tìm ra:

public static void main(String[] args) {

    Thread parkingThread = new Thread(() -> {
        System.out.println("Will go to sleep...");
        sleepTwoSeconds();
        System.out.println("Parking...");
        // this call will return immediately since we have called  LockSupport::unpark
        // before this method is getting called, making the permit available
        LockSupport.park();
        System.out.println("After parking...");
    });

    parkingThread.start();

    // hopefully this 1 second is enough for "parkingThread" to start
    // _before_ we call un-park
    sleepOneSecond();
    System.out.println("Un-parking...");
    // making the permit available while the thread is running and has not yet
    // taken this permit, thus "LockSupport.park" will return immediately
    LockSupport.unpark(parkingThread);

}

private static void sleepTwoSeconds() {
    try {
        Thread.sleep(1000 * 2);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private static void sleepOneSecond() {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}    

Mã tự nói lên chính nó, threadđang chạy nhưng chưa được gọi LockSupport.park, trong khi một số luồng khác gọi LockSupport.unparknó - do đó làm cho giấy phép khả dụng. Sau đó, chúng tôi gọi LockSupport.parkvà điều đó sẽ trả lại ngay lập tức kể từ khi có giấy phép.

Một khi bạn nghĩ về nó, điều này hơi nguy hiểm, nếu bạn để lộ chuỗi của mình cho một số mã bạn không kiểm soát và mã đó gọi LockSupport.unparktrong khi bạn parksau đó - nó có thể không hoạt động.


Điểm rất hay, tôi đã nghĩ rằng một hoạt động cấp phép - tức là gọi unark () - chỉ có liên quan khi một luồng đang được đậu.
Alfred Xiao

@AlfredXiao đồng ý, đây là điều khiến tôi cũng ngạc nhiên, nhưng nó cũng có lý, tôi đoán vậy.
Eugene

1

Theo tôi hiểu, "giấy phép" chỉ là một đối tượng đại diện cho việc một Chủ đề có thể được "bỏ đánh dấu" hay không. Và điều này được kiểm tra bởi chính Chủ đề (hoặc de JRE khi bạn cố gắng đậu một Chủ đề) Điều "được tiêu thụ", tôi hiểu rằng giấy phép sẽ biến mất và Chủ đề không bị vô hiệu hóa.

Tôi nghĩ bạn nên tìm hiểu thêm một chút về đa luồng .. Hãy coi nó như một bộ phân phối với Đối tượng được gọi là "giấy phép". Bạn yêu cầu một Thread để đậu, và Thread kiểm tra bộ phân phối, nếu có "giấy phép" thì Thread sẽ lấy nó và rời đi (không đậu). Nếu không có "giấy phép" trong bộ phân phối, Chủ đề sẽ được sử dụng cho đến khi có "giấy phép" (và bạn có thể đặt "giấy phép" vào bộ phân phối unpark.

Đối với việc sử dụng CPU / bộ nhớ, tôi nghĩ rằng điều đó phụ thuộc vào hệ điều hành, v.v.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.