全部的同步場景都是基於鎖。鎖在併發編程中發揮重要做用。
我是李福春,我在準備面試,今天的題目是:
java
synchronized底層是如何實現的?c++
答: synchronized是在底層的jvm中實現的,即c++寫的,synchronized的實現是基於一對monitorenter, monitorexit指令實現的,monitor對象是同步的基本實現單元。
在java6中,monitor依靠操做系統提供的內部互斥鎖,須要在用戶態空間和內核態空間切換,因此同步操做是一個比較重的操做,開銷比較大。
在java7以後,monitor有三種不一樣的實現,即偏斜鎖,輕量級鎖,重量級鎖。
基於對象頭的markword,標記上偏向的線程id, 在沒有競爭的條件下,使用的是偏斜鎖;
當有多個線程來競爭偏斜鎖,基於cas對對象頭的markword來進行競爭,若是拿到了,升級爲輕量級鎖。
沒拿到則升級爲重量級鎖;
鎖降級發生在jvm進入安全點檢查的時候,對monitor進行降級。
面試
對象頭結構:
編程
sharedRuntime.cpp 解釋器和編譯器的運行時基類。安全
Handle h_obj(THREAD, obj); if (UseBiasedLocking) { // Retry fast entry if bias is revoked to avoid unnecessary inflation ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK); } else { ObjectSynchronizer::slow_enter(h_obj, lock, CHECK); }
偏斜鎖邏輯代碼:
併發
void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) { if (UseBiasedLocking) { if (!SafepointSynchronize::is_at_safepoint()) { BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD); if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) { return; } } else { assert(!attempt_rebias, "can not rebias toward VM thread"); BiasedLocking::revoke_at_safepoint(obj); } assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now"); } slow_enter(obj, lock, THREAD); }
輕量級鎖:jvm
void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) { markOop mark = obj->mark(); if (mark->is_neutral()) { // 將目前的Mark Word複製到Displaced Header上 lock->set_displaced_header(mark); // 利用CAS設置對象的Mark Word if (mark == obj()->cas_set_mark((markOop) lock, mark)) { TEVENT(slow_enter: release stacklock); return; } // 檢查存在競爭 } else if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) { // 清除 lock->set_displaced_header(NULL); return; } // 重置Displaced Header lock->set_displaced_header(markOopDesc::unused_mark()); ObjectSynchronizer::inflate(THREAD, obj(), inflate_cause_monitor_enter)->enter(THREAD); }
java提供的鎖有哪些
優化
再入讀寫鎖:
spa
public class RWSample { private final Map<String, String> m = new TreeMap<>(); private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock r = rwl.readLock(); private final Lock w = rwl.writeLock(); public String get(String key) { r.lock(); System.out.println("讀鎖鎖定!"); try { return m.get(key); } finally { r.unlock(); } } public String put(String key, String entry) { w.lock(); System.out.println("寫鎖鎖定!"); try { return m.put(key, entry); } finally { w.unlock(); } } // … }
優化的讀寫鎖:StampedLock
代碼以下:
讀取以前先經過validate方法判斷是否進入寫狀態,若是沒有進入寫狀態,不用加讀鎖,避免了開銷;
不然增長讀鎖,保證一致性。
操作系統
public class StampedSample { private final StampedLock sl = new StampedLock(); void mutate() { long stamp = sl.writeLock(); try { write(); } finally { sl.unlockWrite(stamp); } } Data access() { long stamp = sl.tryOptimisticRead(); Data data = read(); if (!sl.validate(stamp)) { stamp = sl.readLock(); try { data = read(); } finally { sl.unlockRead(stamp); } } return data; } // … }
本篇先介紹了synchronized的底層實現原理,介紹了java8中引入的3種級別的鎖,以及鎖升級和降級過程。
而後介紹了java體系中的其它的鎖和優化讀寫鎖使用場景。
原創不易,轉載請註明出處,讓咱們互通有無,共同進步,歡迎溝通交流。