2010-07-13 30 views
7

Tôi đã nhận thấy điều gì đó rất lạ hôm qua. Có vẻ như hai chủ đề đang nhập hai khối đồng bộ khóa trên cùng một đối tượng cùng một lúc.phần đồng bộ không chặn!

Lớp (MyClass) chứa mã có liên quan trông tương tự như sau:

private static int[] myLock = new int[0]; 

protected static int methodA(final long handle, final byte[] sort) { 
    synchronized (myLock) { 
     return xsMethodA(handle, sort); 
    } 
} 

protected static int methodB(final long handle) { 
    synchronized (myLock) { 
     return xsMethodB(handle); 
    } 
} 

Tôi tạo ra một bãi chứa thread của ứng dụng của tôi chạy lớp trên và đã rất ngạc nhiên khi tôi thấy điều này:

"http-8080-136" daemon prio=10 tid=0x00000000447df000 nid=0x70ed waiting for monitor entry [0x00007fd862aea000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at com.MyClass.methodA(MyClass.java:750) 
    - locked <0x00007fd8a6b8c790> (a [I) 
    at com.SomeOtherClass.otherMethod(SomeOtherClass.java:226) 
    ... 

"http-8080-111" daemon prio=10 tid=0x00007fd87d1a0000 nid=0x70c8 waiting for monitor entry [0x00007fd86e15f000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at com.MyClass.methodB(MyClass.java:991) 
    - locked <0x00007fd8a6b8c790> (a [I) 
    at com.SomeOtherClass.yetAnotherMethod(SomeOtherClass.java:3231) 
    ... 

(Tôi đã thay đổi tên lớp và phương thức cho trường hợp đơn giản, do đó đừng nhầm lẫn với tên ngớ ngẩn.)

Có vẻ như là ead http-8080-136 và http-8080-111 đều có khóa trên myLock. Nó là cùng một đối tượng như địa chỉ đối tượng là giống nhau: 0x00007fd8a6b8c790. Java Runtime Đặc điểm kỹ thuật nói này về từ khóa synchronized:

Một tuyên bố đồng bộ có được một khóa lẫn nhau-trừ (§17.1) thay mặt cho các chủ đề thực hiện, thực hiện một khối, sau đó ra mắt khóa. Trong khi chuỗi thực thi sở hữu khóa, không có chuỗi nào khác có thể lấy khóa. [The Java Language Specification, 14.19]

Vậy làm thế nào điều này thậm chí có thể?

Có 44 chủ đề khác trong chuỗi kết thúc "chờ" cho khóa. Đây là cách trông giống như một chuỗi đang chờ:

"http-8080-146" daemon prio=10 tid=0x00007fd786dab000 nid=0x184b waiting for monitor entry [0x00007fd8393b6000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at com.MyClass.methodC(MyClass.java:750) 
    - waiting to lock <0x00007fd8a6b8c790> (a [I) 
    at com.SomeOtherClass.yetAnoterMethod2(SomeOtherClass.java:226) 

Trả lời

4

Tôi đã hỏi những câu hỏi tương tự trong danh mục hotspot-dev gửi thư và nhận được một câu trả lời rất goot từ Christopher Phillips:


Hi Eduard

Tôi nghĩ rằng nó là bãi chứa thread được gây hiểu lầm .

Nếu bạn thực sự nghĩ rằng 2 trong khóa đồng thời, bạn nên có thể nhận được một gcore (mà là bên ngoài nhất quán).

Tình trạng mà bạn nhìn thấy "chờ đợi entry màn hình" thực sự là MONITOR_WAIT mà có thể đại diện cho đoạn mã sau trước khi mua thực tế của một khóa nóng: (xem thêm OSThreadContendState trong osThread.hpp) gọi từ: src/share/vm/runtime/Synchronizer.cpp

3413  OSThreadContendState osts(Self->osthread()); 
3414  ThreadBlockInVM tbivm(jt); 
3415 
3416  Self->set_current_pending_monitor(this); 
3417 
3418  // TODO-FIXME: change the following for(;;) loop to straight-line code. 
3419  for (;;) { 
3420  jt->set_suspend_equivalent(); 
3421  // cleared by handle_special_suspend_equivalent_condition() 
3422  // or java_suspend_self() 
3423 
3424  EnterI (THREAD) ; 
3425 
3426  if (!ExitSuspendEquivalent(jt)) break ; 
3427 
3428  // 
3429  // We have acquired the contended monitor, but while we were 
3430  // waiting another thread suspended us. We don't want to enter 
3431  // the monitor while suspended because that would surprise the 
3432  // thread that suspended us. 

Chris

1

Làm thế nào là kết xuất chuỗi? Nếu các chủ đề không bị tạm dừng, quyền sở hữu khóa có thể đã thay đổi giữa việc bán một chuỗi và chuỗi tiếp theo.

+0

Bằng cách gửi tín hiệu QUIT để quá trình này. Tôi không biết làm thế nào Sun VM hoạt động trong quá trình đổ thread. Nhưng tôi cho rằng quá trình này bị tạm dừng. Nếu không, bạn sẽ nhận được một chuỗi không phù hợp. –

+0

Tôi biết cho IBM JVM này không nhất thiết phải đúng, không chắc chắn về SUN, tuy nhiên, chắc chắn một cái gì đó để ghi nhớ. –

+0

Trang web này tuyên bố rằng tất cả các chủ đề bị tạm dừng: http://expertodev.wordpress.com/2009/05/30/how-to-take-java-thread-dump/ –

0

Tôi nghĩ rằng thông tin có liên quan là: "đang chờ mục nhập màn hình", giống nhau cho cả hai chủ đề. Kể từ khi cả hai chủ đề (trong dump thread) được đánh dấu chủ đề deamon, tôi đoán cũng phải có một thread chính chạy cùng một lúc. Có thể chủ đề chính là chủ sở hữu màn hình hiện tại đã chặn hai luồng khác không?

+0

Không, chủ đề chính không làm gì cả. Ngay cả khi chủ đề chính sẽ giữ khóa, đặc điểm kỹ thuật không phân biệt giữa chủ đề chính và deamon. Chỉ một chủ đề được phép sở hữu một khóa. –

+0

Tôi đồng ý, chỉ một chuỗi được phép lấy khóa và vào phần quan trọng (theo đặc điểm kỹ thuật). Cả hai chủ đề deamon là * chờ đợi * cho khóa, như đã nêu trong kết xuất chuỗi. Bạn có chắc chắn, không có chủ đề nào khác hiện đang giữ khóa? – Javaguru

+0

Hai chủ đề http-8080-136 và http-8080-111 đang giữ khóa. Có 44 chủ đề khác trong chuỗi kết thúc "chờ" cho khóa. –

0

Chúng không có khóa, nếu không bạn sẽ thấy xsMethodA hoặc xsMethodB trong một chồng xếp chồng.

+0

Vậy tại sao có sự khác biệt giữa các chủ đề http-8080-111 và http-8080-146? –

+0

Và: ThreadDumpAnalyzer liệt kê cả hai luồng (http-8080-136, http-8080-111) dưới dạng "bị khóa". –

+0

Tôi có nghĩa là tiêu đề "được đồng bộ hóa không chặn" là sai. Có thể bạn có nghĩa là "khối khối đồng bộ khi không có ai giữ khóa"? –

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