2009-07-09 27 views
11

Một chút trợ giúp, vui lòng xem xét mã bit bên dưới.Khóa Reentrant

public class Widget { 
    public synchronized void doSomething() { 
     ... 
    } 
} 

public class LoggingWidget extends Widget { 
    public synchronized void doSomething() { 
     System.out.println(toString() + ": calling doSomething"); 
     super.doSomething(); 
    } 
} 

Tôi đọc rằng khi doSomething() trong LoggingWidget được gọi, JVM sẽ cố gắng lấy khóa trên LoggingWidget trước và sau đó trên Widget.

Tôi rất tò mò muốn biết lý do. Có phải vì JVM biết rằng doSomething() có một cuộc gọi đến super.doSomething() hoặc bởi vì gọi một phương thức lớp con sẽ luôn có được một khóa trên lớp cha.

Cheers

+0

Bạn nên đăng tham chiếu đến nơi bạn đọc này vì nó không đúng :-) –

+0

Cảm ơn sự giúp đỡ của bạn. Tôi hiểu nhầm lời giải thích về khóa reentrant.Sau khi đọc lời giải thích của bạn, tôi đã quay trở lại nguồn (một trích đoạn từ cuốn sách Đồng thời trong thực tế) và bây giờ nó có ý nghĩa. – CaptainHastings

Trả lời

9

Bạn đang nhầm lẫn - khóa thu được tại dụ cấp. Chỉ có một khóa trong ví dụ của bạn bởi vì chỉ có một trường hợp được tạo ra khi bạn nói:

Widget w = new LoggingWidget 

Bạn có thể xem ổ khóa (còn được gọi là màn, mutexes hoặc Cột) như là cá nhân " đính kèm "vào mọi đối tượng đối tượng trong JVM.

Nếu bạn có phương thức synchronized khác trên lớp con LoggingWidget, bạn sẽ thấy điều này là đúng. Nó sẽ không thể gọi phương thức này (mới) và phương thức doSomething cùng một lúc [với các luồng khác nhau trên cùng một đối tượng].

Điều này cũng đúng với phương thức synchronized khác trên lớp cha (nghĩa là nó không bị ảnh hưởng theo bất kỳ cách nào bằng các phương thức bị ghi đè).

1

Chỉ có một trường hợp để khóa, ví dụ của LoggingWidget, không bao giờ có một phiên bản thực tế của Widget.

Khóa được lấy khi bạn gọi LoggingWidget.doSomething() và khi bạn đã có khóa khi bạn gọi super.doSomething() phương thức đó được thực hiện như bình thường.

+0

Cảm ơn Nick, có ý nghĩa. – CaptainHastings

5
public synchronized void doSomething() { 
    System.out.println(toString() + ": calling doSomething"); 
    super.doSomething(); 
} 

là giống như:

public void doSomething() { 
    synchronized (this) { 
     System.out.println(toString() + ": calling doSomething"); 
     super.doSomething(); 
    } 
} 

Bạn đang khóa trên dụ, không phải là lớp học. Vì vậy, khi super.doSomething() được gọi, bạn đã có trường hợp đó bị khóa.

+0

Cảm ơn, khi bài hát đi, tôi có thể thấy rõ ràng bây giờ ... – CaptainHastings

0

Reentrancy hoạt động bằng cách mua khóa lần đầu tiên. Khi một luồng thu được khóa, nó được biết đến trong jvm. Khi nhập một khối mã được đồng bộ hóa với chuỗi hiện đang giữ khóa, chúng được phép tiếp tục mà không cần lấy lại khóa. Sau đó, jvm tăng một lượt truy cập mỗi hành động reentrant, tiếp tục giảm khi thoát khỏi khối đó cho đến khi số đếm bằng không. Khi đếm là zero, khóa được giải phóng.

0

B.Goetz - "JJava Concurrency in Practice" nếu ổ khóa nội tại không reentrant, cuộc gọi đến super.doSomething sẽ không bao giờ có thể có được khóa bởi vì nó sẽ được coi là đã được tổ chức, và thread sẽ vĩnh viễn gian hàng chờ đợi cho một khóa nó không bao giờ có thể có được. Reentrancy cứu chúng ta khỏi bế tắc trong những tình huống như thế này.

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