2009-12-14 24 views
15

Là một lập trình viên C++ trở nên quen thuộc hơn với Java, có một chút kỳ quặc đối với tôi khi thấy hỗ trợ mức ngôn ngữ để khóa các đối tượng tùy ý mà không có bất kỳ kiểu khai báo nào mà đối tượng hỗ trợ khóa như vậy. Tạo mutexes cho mọi đối tượng có vẻ giống như một chi phí nặng được tự động chọn tham gia. Bên cạnh việc sử dụng bộ nhớ, mutexes là một tài nguyên giới hạn OS trên một số nền tảng. Bạn có thể quay khóa nếu không có sẵn mutex nhưng đặc tính hiệu suất của nó khác nhau đáng kể, điều mà tôi mong đợi sẽ làm tổn thương khả năng dự đoán.JVM có tạo ra một mutex cho mọi đối tượng để thực hiện từ khóa 'đồng bộ' không? Nếu không, làm thế nào?

JVM có đủ thông minh trong mọi trường hợp để nhận ra rằng một đối tượng cụ thể sẽ không bao giờ là đích của từ khóa được đồng bộ hóa và do đó tránh tạo ra mutex không? Các mutex có thể được tạo ra một cách lười biếng, nhưng điều đó đặt ra một vấn đề khởi động mà chính nó đòi hỏi một mutex, và thậm chí nếu nó đã được làm việc xung quanh tôi giả sử vẫn sẽ có một số chi phí để theo dõi liệu một mutex đã được tạo ra hay chưa. Vì vậy, tôi giả định nếu như một tối ưu hóa là có thể, nó phải được thực hiện tại thời gian biên dịch hoặc khởi động. Trong C++, việc tối ưu hóa như vậy sẽ không thể thực hiện được do mô hình biên dịch (bạn không thể biết liệu khóa cho một đối tượng có được sử dụng trên các biên giới thư viện) hay không, nhưng tôi không biết đủ về biên dịch Java và liên kết để biết nếu áp dụng cùng một giới hạn.

+0

Tôi chắc chắn 'đồng bộ' được xử lý nội bộ trong JVM, thay vì dựa vào tài nguyên ở cấp hệ điều hành. –

+0

Điều đó hoàn toàn không đúng. Tôi đồng ý rằng nó có thể được thực hiện theo bất kỳ cách nào mà JVM muốn, nhưng JVM nhất thiết phải dựa vào liên lạc ở cấp độ hệ điều hành ở đâu đó trong nội bộ. Bạn có thể viết lớp mutex của riêng bạn mà quay khóa, nhưng nếu bạn muốn trình lên lịch cho hệ điều hành đặt các chủ đề vào chế độ ngủ và đánh thức chúng một cách thích hợp, tại một số điểm bạn phải nói với hệ điều hành về mutex của bạn và các loại đăng ký đó là giới hạn nguồn. –

+0

Bạn không cần phải nói cho hệ điều hành về mutex của bạn - bạn chỉ cần nói với nó khi các chủ đề nhất định cần được đánh thức. –

Trả lời

15

Nói như ai đó đã nhìn cách mà một số JVM thực hiện khóa ...

Cách tiếp cận thông thường là bắt đầu với một vài bit dự trữ trong từ tiêu đề của đối tượng. Nếu đối tượng không bao giờ bị khóa, hoặc nếu nó bị khóa nhưng không có tranh chấp nó vẫn như vậy. Nếu và khi tranh chấp xảy ra trên một đối tượng bị khóa, JVM sẽ thổi phồng khóa vào cấu trúc dữ liệu mutex toàn diện và nó vẫn như vậy trong suốt thời gian tồn tại của đối tượng.

EDIT - Tôi vừa nhận thấy rằng OP đang nói về các mutex được OS hỗ trợ. Trong các ví dụ mà tôi đã xem xét, các mutex không uninflated được thực hiện trực tiếp bằng cách sử dụng các lệnh CAS và các hàm tương tự, thay vì sử dụng các hàm thư viện pthread, v.v.

+0

Bởi thổi phồng, bạn có nghĩa là một cái gì đó đang xảy ra như tối ưu hóa chuỗi nhỏ trong C/C + +? (http://tulrich.com/rants-2009.html#d2009-01-03T00:00:00Z) Về cơ bản, thông tin bắt đầu khi các bit được đóng gói bên trong một từ, nhưng khi các điều kiện nhất định được đáp ứng thì từ đó bắt đầu được diễn giải như một con trỏ tới một đối tượng có nhiều trường hơn? –

+0

Khái niệm, vâng. –

+1

Chỉ sử dụng hướng dẫn CAS, làm thế nào để bạn có được bộ lập lịch hệ điều hành để đặt một luồng vào chế độ ngủ? –

2

Bạn không bao giờ có thể chắc chắn rằng một đối tượng sẽ không bao giờ được sử dụng làm khóa (xem xét sự phản chiếu). Thông thường mỗi đối tượng có một tiêu đề với một số bit dành riêng cho khóa. Có thể thực hiện nó sao cho tiêu đề chỉ được thêm khi cần, nhưng có chút phức tạp và bạn có thể cần tiêu đề nào đó (lớp (tương đương với "vtbl" và kích cỡ phân bổ trong C++), mã băm và thu gom rác) .

Here's a wiki page on the implementation of synchronisation in the OpenJDK.

(Theo ý kiến ​​của tôi, thêm một khóa để mọi đối tượng đã là một sai lầm.)

+0

Có nơi nào tôi có thể đọc thêm về 'tiêu đề' này không? Vì bạn nói rằng bạn có thể cần nó anyway tôi giả sử nó được sử dụng cho những thứ khác hơn là khóa. –

+0

Tất cả đều thuộc nguồn GPL/JRL/JIUL! –

+0

Đúng, nhưng tôi hy vọng rằng nếu các lập trình viên Java nói chung quan tâm đến câu trả lời cho những câu hỏi này, tôi cho rằng ai đó đã viết ra một thứ dễ tiêu hóa hơn hàng triệu dòng mã nguồn. Nếu tôi trở nên đủ quan tâm và có đủ thời gian tôi có thể làm điều đó cuối cùng mặc dù;) –

2

Đây thực sự là một chi tiết thực hiện của JVM và các JVM khác nhau thực hiện nó một cách khác nhau. Tuy nhiên, nó chắc chắn là không phải là một cái gì đó có thể được tối ưu hóa tại thời gian biên dịch, kể từ khi liên kết Java lúc chạy, và điều này là có thể cho mã chưa biết trước đó để có được một tổ chức của một đối tượng được tạo trong mã cũ hơn và bắt đầu đồng bộ trên nó.

Lưu ý rằng trong Java lingo, nguyên thủy đồng bộ hóa được gọi là "giám sát" thay vì mutex và được hỗ trợ bởi các hoạt động bytecode đặc biệt. Có một lời giải thích khá chi tiết here.

+0

Liên kết tốt đẹp, cảm ơn. –

1

JVM có thể sử dụng hướng dẫn so sánh và trao đổi trực tiếp không?giả sử mỗi đối tượng có một trường lockingThreadId lưu trữ các id của thread đó là khóa nó,

while(compare_and_swap (obj.lockingThreadId, null, thisThreadId) != thisTheadId) 
    // failed, someone else got it 
    mark this thread as waiting on obj. 
    shelf this thead 

//out of loop. now this thread locked the object 

do the work 

obj.lockingThreadId = null; 
wake up threads waiting on the obj 

đây là một mô hình đồ chơi, nhưng nó dường như không quá đắt, và không không phụ thuộc vào hệ điều hành.

+1

P.S. sự lựa chọn thiết kế cho phép bất kỳ đối tượng nào bị khóa có lẽ là sai. có thể chỉ một số loại đối tượng nhất định phải được phép cho mục đích đồng bộ hóa, giống như chỉ một số loại đối tượng nhất định có thể được ném. 'sync (a_normal_object) {}' rất khó hiểu đối với những người mới học, họ nghĩ rằng đối tượng được bảo vệ và không có luồng nào khác có thể ghi vào nó. nếu họ phải sử dụng một vật thể khóa khác để bảo vệ vật thể bình thường của mình, thì sẽ dễ hiểu hơn những gì đang diễn ra. – irreputable

+1

JVM phải liên lạc với hệ điều hành tại một thời điểm nào đó để có thể chuyển sang chế độ ngủ và có thể đánh thức nó trở lại, vì bộ lập lịch hệ điều hành chịu trách nhiệm cho điều đó. Nếu JVM sử dụng nó trực tiếp, tất cả các waits sẽ là các khóa spin, không hiệu quả trong thời gian chờ đợi lâu. Một thực hiện thực sự có thể quay cho một chút sau đó đi ngủ trên một semaphore thực từ hệ điều hành. –

+0

"Nếu JVM sử dụng nó trực tiếp" <- by 'it' Tôi có nghĩa là hướng dẫn CAS –

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