cuốn sách gpt4 ai đã làm

Nguyên tắc triển khai cơ bản của khóa thiên vị đồng bộ hóa

In lại Tác giả: Người biết Thời gian cập nhật: 2024-03-13 05:57:03 31 4
mua khóa gpt4 Nike

1 Ý nghĩa của khóa thiên vị

Khi không có sự cạnh tranh đa luồng, các đường dẫn thực thi khóa nhẹ không cần thiết sẽ bị giảm. Trong hầu hết các trường hợp, không những không có sự cạnh tranh đa luồng đối với các khóa mà còn cùng một luồng luôn lấy được khóa nhiều lần. Để làm cho chi phí hiệu năng của các luồng có được khóa thấp hơn, các khóa thiên vị được đưa ra.

Khóa thiên vị chủ yếu được sử dụng để tối ưu hóa cạnh tranh khi cùng một luồng áp dụng cho cùng một khóa nhiều lần. Nghĩa là, khi đối tượng được coi là khóa đồng bộ hóa và một luồng lấy khóa, hãy đặt ID luồng của luồng trong Mark Word và. có đặt khóa thiên vị hay không 1. Bit cờ khóa được đặt thành 01 và các thông tin khác. Tại thời điểm này, Mark Word lưu trữ thông tin trạng thái khóa thiên vị.

hiện hữu:

  • Tạo một luồng và thực hiện giám sát vòng lặp trong luồng
  • Hoặc khi vận hành bộ sưu tập an toàn theo luồng trong một luồng

Cùng một luồng cần lấy và giải phóng khóa mỗi lần và mỗi thao tác sẽ chuyển đổi giữa chế độ người dùng và chế độ kernel.

Các kịch bản để có được khóa thiên vị:

Tạo Bản ghi khóa trong ngăn xếp luồng của riêng bạn và sau đó Tham chiếu đối tượng trỏ đến tiêu đề đối tượng. Tại thời điểm này, Bản ghi khóa và tiêu đề đối tượng được kết nối:

①: Đầu tiên hãy xác định xem Thread ID của Mard Word có giá trị hay không

  • Nếu không, điều đó có nghĩa là tài nguyên hiện tại không bị chiếm bởi các luồng khác. Ghi lại ID luồng hiện tại và thông tin khác vào Mark Word (điều này yêu cầu CAS, nhiều luồng có thể sửa đổi Mark Word và cần đảm bảo tính nguyên tử)

  • Nếu có, điều đó có nghĩa là tài nguyên hiện tại đã bị chiếm bởi luồng và bạn cần xác định xem luồng đó có phải là của riêng bạn không

  • Nếu ID luồng là của riêng bạn, điều đó có nghĩa là nó có thể được đăng nhập lại và lấy trực tiếp (tại thời điểm này, Bản ghi khóa mới sẽ tiếp tục được tạo trong ngăn xếp luồng của riêng bạn)

  • ID luồng không phải của riêng bạn, cho biết rằng các luồng khác cạnh tranh và luồng hiện đang giữ khóa thiên vị cần được thu hồi, nghĩa là khóa chỉ được giải phóng khi các luồng khác cố gắng lấy khóa thiên vị.

Việc thu thập và giải phóng các khóa hạng nhẹ phụ thuộc vào nhiều hoạt động CAS, trong khi các khóa thiên vị chỉ dựa vào một lần thay thế CAS.ID chủ đề.

Một khi nó xuất hiệnNhiều chủ đề cạnh tranhKhóa thiên vị phải được thu hồi, vì vậy:

Mức tiêu thụ hiệu suất của việc hủy khóa thiên vị phải < mức tiêu thụ hiệu suất của hoạt động nguyên tử CAS đã lưu trước đó

Ngược lại, cái được nhiều hơn cái mất!

JDK6 cho phép khóa thiên vị theo mặc định, có thể được thông qua-XX:-Sử dụngBiasedLockingVô hiệu hóa khóa thiên vị.

2 Mua lại khóa thiên vị

Lối vào khóa thiên vị, trong tệp syncer.cpp

Trình đồng bộ hóa đối tượng::fast_enter

phụ thuộc vàoBiasedLocking::revoke_and_rebiashoàn thành

2.1 markOop mark = obj->mark()

Lấy dấu dữ liệu markOop của đối tượng, tức là Mark Word của tiêu đề đối tượng

2.2 Xác định xem dấu có bị sai lệch hay không

Cờ khóa của khóa thiên vị của nhãn hiệu là 01

2.3 Xác định trạng thái của JavaThread trong dấu

  • Nếu nó trỏ đến luồng hiện tại, hãy thực thi khối mã được đồng bộ hóa
  • Nếu trống thì đi 4
  • Nếu nó trỏ đến chủ đề khác, hãy chuyển đến 5

2.4 Thực hiện các lệnh nguyên tử CAS

Đặt dấu JavaThread thành ID luồng hiện tại.

Nếu CAS thành công, thực thi khối mã đồng bộ, nếu không thì chuyển sang bước 5.

2.5 Không thực thi được CAS

Điều đó có nghĩa là hiện có nhiều luồng cạnh tranh để giành khóa. Khi đạt đến điểm an toàn toàn cầu (điểm an toàn), luồng nhận được khóa thiên vị sẽ bị tạm dừng, khóa thiên vị sẽ bị thu hồi và nó sẽ được nâng cấp lên mức nhẹ. khóa.

Sau khi nâng cấp hoàn tất, luồng bị chặn ở điểm an toàn tiếp tục thực thi khối mã được đồng bộ hóa.

BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool try_rebias, TRAPS) { khẳng định(!SafepointSynchronize::is_at_safepoint(), "không được gọi khi đang ở điểm an toàn" // Chúng ta có thể hủy bỏ các thành kiến ​​​​của thành kiến ​​ẩn danh"); đối tượng // đủ hiệu quả để chúng ta không khiến các lệnh thu hồi này // cập nhật các phương pháp phỏng đoán vì làm như vậy có thể gây ra việc thu hồi số lượng lớn // không mong muốn (tốn kém) // step1 markOop mark = obj->mark(); if (mark->is_biased_anonymous() && !attempt_rebias) { // Có lẽ chúng tôi đang cố gắng thu hồi. độ lệch của đối tượng này do // tính toán mã băm nhận dạng. Cố gắng hủy bỏ độ lệch // mà không có điểm an toàn. Điều này có thể thực hiện được nếu chúng ta có thể so sánh và trao đổi thành công một tiêu đề không thiên vị vào đối tượng. đánh dấu từ của // đối tượng, nghĩa là không có luồng nào khác chạy đua để đạt được // độ lệch của đối tượng. markOopbiased_value = mark; ; markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark); if (res_mark ==biased_value) { return BIAS_REVOKED; } } else if (mark->has_bias_pattern()) { Klass* k = obj->klass(); >prototype_header(); if (!prototype_header->has_bias_pattern()) { // Đối tượng này có xu hướng cũ từ trước khi xảy ra việc thu hồi hàng loạt // đối với loại dữ liệu này. Việc cập nhật // chẩn đoán vào thời điểm này là vô nghĩa, vì vậy chỉ cần cập nhật tiêu đề bằng // CAS. Nếu chúng tôi thất bại trong cuộc đua này, xu hướng của đối tượng. đã bị thu hồi // bởi một luồng khác nên chúng tôi chỉ cần quay lại và để người gọi xử lý // với nó. Atomic::cmpxchg_ptr(prototype_header, obj->mark_addr(), mark); khẳng định(!(*(obj->mark_addr()))->has_bias_pattern(), "ngay cả khi chúng tôi đua, vẫn nên bị thu hồi"); trả về BIAS_REVOKED } khác nếu (prototype_header->bias_epoch() != mark->bias_epoch()) { // Kỷ nguyên của xu hướng này đã hết cho thấy rằng // đối tượng thực sự không thiên vị. Tùy thuộc vào việc chúng ta cần // phục hồi hay thu hồi độ lệch của đối tượng này, chúng ta có thể thực hiện // một cách hiệu quả. với CAS là đủ nên chúng ta không nên cập nhật // chẩn đoán. Điều này thường được thực hiện trong mã hợp ngữ nhưng chúng ta // có thể đạt đến điểm này do có nhiều điểm khác nhau trong thời gian chạy // cần phải thu hồi các thành kiến ​​nếu. (attempt_rebias) { khẳng định(THREAD->is_Java_thread(), ""); markOopbiased_value = mark; markOop rebiased_prototype = markOopDesc::encode((JavaThread*) THREAD, mark->age(), Prototype_header->bias_epoch()) ; markOop res_mark = (markOop) Atomic::cmpxchg_ptr(rebiased_prototype, obj->mark_addr(), mark); if (res_mark ==biased_value) { return BIAS_REVOKED_AND_REBIASED; } } else { markOopbiased_value = mark; markOopDesc::prototype()->set_age(mark->age()); markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype,obj->mark_addr(), mark); if (res_mark ==biased_value) { return BIAS_REVOKED; } } } } HeuristicsResult heuristics = update_heuristics(obj(), try_rebias); if (heuristics == HR_NOT_BIASED) { return NOT_BIASED; nếu (heuristic == HR_SINGLE_REVOKE) { Klass *k = obj->klass(); markOop nguyên mẫu_header = k->prototype_header(); if (mark->biased_locker() == THREAD && nguyên mẫu_header->bias_epoch() == mark->bias_epoch() ) { // Một luồng đang cố gắng thu hồi sự thiên vị của một đối tượng thiên về // đối với nó, một lần nữa có thể là do một mã băm nhận dạng // tính toán. Một lần nữa, chúng ta có thể tránh điểm an toàn trong trường hợp này // vì chúng ta sẽ chỉ đi theo ngăn xếp của riêng mình. Không có // cuộc chạy đua nào xảy ra trong các luồng khác vì chúng ta // không đạt được điểm an toàn nào trong đó. đường dẫn thu hồi. // Đồng thời kiểm tra kỷ nguyên vì ngay cả khi các luồng khớp nhau, một luồng khác // có thể đi kèm với CAS để đánh cắp độ lệch của một đối tượng có // kỷ nguyên cũ. ResourceMark rm; tty->print_cr("Thu hồi độ lệch bằng cách di chuyển ngăn xếp của riêng tôi:"); } EventBiasedLockSelfRevocation; ) THREAD)->set_cached_monitor_info(NULL); khẳng định(cond == BIAS_REVOKED, "tại sao không?"); if (event. Should_commit()) { event.set_lockClass(k); event.commit(); } return cond; } else { Sự kiện EventBiasedLockRevocation; THREAD); VMThread::execute(&revoke); (event. Should_commit() && (revoke.status_code() != NOT_BIASED)) { event.set_lockClass(k); // Trừ 1 để khớp với id của các sự kiện đã cam kết bên trong safepoint event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); sự kiện.set_previousOwner(revoke.biased_locker()); event.commit(); } return revoke.status_code(); } } khẳng định((heuristics == HR_BULK_REVOKE) || (heuristics == HR_BULK_REBIAS), "?"); Sự kiện EventBiasedLockClassRevocation; CHỦ ĐỀ, (heuristic == HR_BULK_REBIAS), try_rebias); VMThread::execute(&bulk_revoke); if (event. Should_commit()) { event.set_revokedClass(obj->klass()); event.set_disableBiasing((heuristics != HR_BULK_REBIAS)); 1 để khớp với id của các sự kiện đã cam kết bên trong điểm an toàn event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); event.commit() } return Bulk_revoke.status_code();một lần nữa có thể là do tính toán mã băm nhận dạng //. Chúng ta lại có thể tránh điểm an toàn trong trường hợp này // vì chúng ta sẽ chỉ đi theo ngăn xếp của chính mình. Không có // cuộc đua nào xảy ra trong các luồng khác vì chúng ta // không đạt đến điểm an toàn trong đường dẫn thu hồi. // Ngoài ra, hãy kiểm tra kỷ nguyên vì ngay cả khi các luồng khớp nhau, một luồng khác // có thể đi kèm với CAS để đánh cắp độ lệch của một đối tượng có // kỷ nguyên cũ if. (TraceBiasedLocking) { tty->print_cr("Thu hồi độ lệch bằng cách di chuyển ngăn xếp của riêng tôi:"); } EventBiasedLockSelfRevocation event; BiasedLocking::Condition cond = revoke_bias(obj(), false, false, (JavaThread*) THREAD); ((JavaThread*) THREAD)->set_cached_monitor_info(NULL); khẳng định (cond == BIAS_REVOKED, "tại sao không?"); if (event. Should_commit()) { event.set_lockClass(k); event.commit(); return cond; } else { EventBiasedLockRevocation; , (JavaThread*) THREAD); VMThread::execute(&revoke); (event. Should_commit() && (revoke.status_code() != NOT_BIASED)) { event.set_lockClass(k); // Trừ 1 để khớp với id của các sự kiện đã cam kết bên trong safepoint event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); sự kiện.set_previousOwner(revoke.biased_locker()); event.commit(); } return revoke.status_code(); } } khẳng định((heuristics == HR_BULK_REVOKE) || (heuristics == HR_BULK_REBIAS), "?"); Sự kiện EventBiasedLockClassRevocation; CHỦ ĐỀ, (heuristic == HR_BULK_REBIAS), try_rebias); VMThread::execute(&bulk_revoke); if (event. Should_commit()) { event.set_revokedClass(obj->klass()); event.set_disableBiasing((heuristics != HR_BULK_REBIAS)); 1 để khớp với id của các sự kiện đã cam kết bên trong điểm an toàn event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); event.commit() } return Bulk_revoke.status_code();một lần nữa có thể là do tính toán mã băm nhận dạng //. Chúng ta lại có thể tránh điểm an toàn trong trường hợp này // vì chúng ta sẽ chỉ đi theo ngăn xếp của chính mình. Không có // cuộc đua nào xảy ra trong các luồng khác vì chúng ta // không đạt được điểm an toàn nào trong đường dẫn thu hồi. // Ngoài ra, hãy kiểm tra kỷ nguyên vì ngay cả khi các luồng khớp nhau, một luồng khác // có thể đi kèm với CAS để đánh cắp độ lệch của một đối tượng có // kỷ nguyên cũ if. (TraceBiasedLocking) { tty->print_cr("Thu hồi độ lệch bằng cách di chuyển ngăn xếp của riêng tôi:"); } EventBiasedLockSelfRevocation sự kiện; ((JavaThread*) THREAD)->set_cached_monitor_info(NULL); khẳng định (cond == BIAS_REVOKED, "tại sao không?"); if (event. Should_commit()) { event.set_lockClass(k); event.commit(); } return cond; } else { EventBiasedLockRevocation; , (JavaThread*) THREAD); VMThread::execute(&revoke); (event. Should_commit() && (revoke.status_code() != NOT_BIASED)) { event.set_lockClass(k); // Trừ 1 để khớp với id của các sự kiện đã cam kết bên trong safepoint event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); sự kiện.set_previousOwner(revoke.biased_locker()); event.commit(); } return revoke.status_code(); } } khẳng định((heuristics == HR_BULK_REVOKE) || (heuristics == HR_BULK_REBIAS), "?"); Sự kiện EventBiasedLockClassRevocation; CHỦ ĐỀ, (heuristic == HR_BULK_REBIAS), try_rebias); VMThread::execute(&bulk_revoke); if (event. Should_commit()) { event.set_revokedClass(obj->klass()); event.set_disableBiasing((heuristics != HR_BULK_REBIAS)); 1 để khớp với id của các sự kiện đã cam kết bên trong điểm an toàn event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); event.commit() } return Bulk_revoke.status_code();set_lockClass(k); // Trừ 1 để khớp với id của các sự kiện đã được cam kết bên trong safepoint event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); } return revoke.status_code(); } } khẳng định((heuristics == HR_BULK_REVOKE) || (heuristics == HR_BULK_REBIAS), "?"); Sự kiện EventBiasedLockClassRevocation; VMThread::execute(&bulk_revoke); if (event. Should_commit()) { event.set_revokedClass(obj->klass()); event.set_disableBiasing((heuristics != HR_BULK_REBIAS)); // Trừ 1 để khớp với id của các sự kiện được cam kết bên trong điểm an toàn event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); event.commit() } return Bulk_revoke.status_code();set_lockClass(k); // Trừ 1 để khớp với id của các sự kiện đã được cam kết bên trong safepoint event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); } return revoke.status_code(); } } khẳng định((heuristics == HR_BULK_REVOKE) || (heuristics == HR_BULK_REBIAS), "?"); Sự kiện EventBiasedLockClassRevocation; VMThread::execute(&bulk_revoke); if (event. Should_commit()) { event.set_revokedClass(obj->klass()); event.set_disableBiasing((heuristics != HR_BULK_REBIAS)); // Trừ 1 để khớp với id của các sự kiện được cam kết bên trong điểm an toàn event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1); event.commit() } return Bulk_revoke.status_code();

3 Hủy khóa thiên vị

Luồng giữ khóa thiên vị sẽ chỉ giải phóng khóa khi các luồng khác cố gắng cạnh tranh khóa thiên vị.

Khóa thiên vị bị hủy bởiBiasedLocking::revoke_at_safepointhoàn thành:

void BiasedLocking::revoke_at_safepoint(Handle h_obj) { khẳng định(SafepointSynchronize::is_at_safepoint(), "chỉ được gọi tại điểm an toàn"); oop obj = h_obj(); = HR_SINGLE_REVOKE) { revoke_bias(obj, false, false, NULL, NULL); } else if ((heuristics == HR_BULK_REBIAS) || (heuristics == HR_BULK_REVOKE)) { Bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL } clean_up_cached_monitor_info(); }
  1. Hành động thu hồi khóa thiên vị phải chờ điểm an toàn toàn cầu (điểm an toàn, điểm tạm dừng chặn tất cả các luồng trong quá trình GC)
  2. Tạm dừng luồng sở hữu khóa thiên vị và xác định xem đối tượng khóa có bị khóa hay không.
  3. Hủy khóa thiên vị và khôi phục về không khóa (bit cờ 01) hoặc khóa nhẹ (bit cờ 00)tình trạng

Khóa thiên vị được bật theo mặc định sau Java 1.6, nhưng nó không được kích hoạt cho đến vài giây sau khi ứng dụng khởi động:

-XX:BiasedLockingStartupDelay=0

Nếu bạn xác định rằng tất cả các khóa trong ứng dụng thường bị tranh chấp, bạn có thể tắt các khóa thiên vị:

XX:-UseBiasedLocking=false (bật theo mặc định)
Phát hành khóa thiên vị

Duyệt qua tất cả các Bản ghi khóa trong ngăn xếp luồng và cắt bỏ ObjectReference, nghĩa là ObjectReference = null.

Đặt ObjectReference thành null, nhưng Mark Word trong tiêu đề đối tượng của đối tượng khóa không thay đổi và nó vẫn thiên về luồng trước đó, do đó khóa vẫn không được giải phóng. Thật vậy, khi luồng thoát khỏi phần quan trọng, khóa. khóa thiên vị không được giải phóng. Điều này là dành cho: Khi bạn cần lấy lại khóa, bạn chỉ cần đánh giá xem đó có phải là khóa lại hay không và bạn có thể nhanh chóng lấy được khóa mà không cần phải CAS mỗi lần. hiệu quả của khóa thiên vị trong trường hợp chỉ có một luồng truy cập vào khóa.

Tóm tắt

  • Khi tài nguyên khóa được truy cập, Bản ghi khóa sẽ được tạo trong ngăn xếp luồng hiện tại và ObjectReference sẽ trỏ đến Mark Word trong tiêu đề đối tượng của đối tượng khóa. Cài đặt này có thể gây ra đa luồng và yêu cầu hoạt động CAS.
  • Khi nhiều luồng cạnh tranh để giành cùng một tài nguyên khóa, việc thu hồi các khóa thiên vị sẽ ảnh hưởng đến hiệu quả.
  • Số lần truy cập lại của các khóa thiên vị phụ thuộc vào số lượng Bản ghi khóa trong ngăn xếp luồng.
  • Nếu khóa thiên vị không được thu hồi, cuối cùng nó sẽ được nâng cấp lên khóa nhẹ.
  • Khi khóa thiên vị thoát ra, Mark Word không được sửa đổi, tức là khóa không được giải phóng.
  • So với các khóa nhẹ, khóa thiên vị không cần thực hiện các thao tác CAS khi cùng một luồng lấy lại khóa, điều này giúp cải thiện hiệu suất (Khóa nhẹ thu được khóa mỗi lần trong cùng một luồng và ở trạng thái không khóa. Tiếp theo, a Hoạt động CAS phải được thực hiện mỗi lần)
  • Khóa thiên vị sẽ chỉ giải phóng khóa khi các luồng khác cố gắng cạnh tranh khóa thiên vị. Chuỗi sẽ không chủ động giải phóng khóa thiên vị.
  • Việc hủy bỏ khóa thiên vị rất phức tạp, điều này trở thành trở ngại cho việc hiểu mã và cản trở việc xây dựng lại hệ thống đồng bộ hóa. Hơn nữa, ngày nay về cơ bản tất cả các hệ thống đa lõi đều được sử dụng và nhược điểm của khóa thiên vị ngày càng nhiều. hiển nhiên, vậyKhóa thiên vị đã bị bỏ trong Java 15
31 4 0
Chứng chỉ ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com
Xem sitemap của VNExpress