Java-併發-鎖-synchronized
Java-併發-鎖-synchronized
摘要
本文會詳細說下synchronized的底層實現原理。
0x01 基本概念
- 每次只能有一個執行緒進入臨界區
- 保證臨界區內共享變數的可見性和有序性
- 成功進入
synchronized
區域的執行緒可以拿到物件的Object-Monitor。具體有3種用法,作用域不同,在後面例子中介紹。 - 對於拿到鎖的執行緒來說,同一個物件的
synchronized
具有可重入性 - 不要將可變物件作為synchronized
- 如果相互等待對方的synchronized 物件,可能出現死鎖
- synchronized鎖是非公平的
注意:最近發現本文所講偏向鎖和輕量級鎖的程式碼分析章節有誤,請大家移駕參閱死磕Synchronized底層實現–概論系列文章,檢視原始碼分析。待後續有時間我會改正本文內容。
前置知識,是鎖優化升級:
- Java中4種synchronized鎖狀態,隨著鎖競爭開始,這幾種鎖之間有鎖升級的關係:
無鎖 -> 偏向鎖 -> 輕量級鎖 -> 重量級鎖
- 鎖只能升級不能降級。這麼做的原因是縮短鎖的獲取釋放週期,提升效率。
關於鎖優化和鎖升級知識的更多詳細內容請點選此文:Java-併發-關於鎖的一切
0x02 實現原理
2.1 引子-synchronized用於物件同步塊
可以用一個簡單程式碼試試:
public class SimpleTest2
{
public static void main(String[] args)
{
Object chengc = new Object();
synchronized (chengc){
int i = 1;
System.out.println("");
}
}
}
然後就是用命令編譯:
$ javac SimpleTest2.java
然後進行反彙編:
$ javap -c SimpleTest2.class
結果如下:
11: monitorenter
12: iconst_1
13: istore_3
14: aload_2
15: monitorexit
synchronized
程式碼塊通過javap
生成的位元組碼中包含 monitorenter
和 monitorexit
指令。也就是說,synchronized
指令可以嘗試獲取物件鎖(object-monitor):
- monitor
每個物件都關聯著一個monitor,只能被唯一獲取monitor許可權的執行緒鎖定。鎖定後,其他執行緒請求會失敗,進入等待集合,執行緒隨之被阻塞。 - monitorenter
這個命令就是用來獲取監視器的許可權,每進入1次就記錄次數加1,也就是同一執行緒說可重入。而其他未獲取到鎖的只能等待。 - monitorexit
擁有該監視器的執行緒才能使用該指令,且每次執行都會將累計的計數減1,直到變為0就釋放了所有權。在此之後其他等待的執行緒就開始競爭該監視器的許可權
在jdk8/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp
中可以找到如下方法:
static void monitorenter(JavaThread* thread, BasicObjectLock* elem);
static void monitorexit (JavaThread* thread, BasicObjectLock* elem);
因為前置知識還不夠,我們程式碼分析先說到這裡。請看完第四章後,在這裡繼續看monitorenter底層實現。
2.2 synchronized用於方法
先說結論,將關鍵字修飾方法,那就會使得該方法的flags
中多出一個ACC_SYNCHRONIZED
。當執行緒執行時就需要去獲取物件監視器,拿到的再開始執行方法。
例項如下:
public class SynchronizedMethodTest
{
public synchronized void synMethod(){
int j = 11;
}
public static synchronized void method() {
System.out.println("Hello World!");
}
}
編譯後再使用javap -verbose SynchronizedMethodTest.class
,部分結果如下:
public synchronized void synMethod();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=1, locals=2, args_size=1
0: bipush 11
2: istore_1
3: return
LineNumberTable:
line 9: 0
line 10: 3
public static synchronized void method();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=0, args_size=0
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Hello World!
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 13: 0
line 14: 8
可以看到兩個synchronized
方法的flags
區域都多了ACC_SYNCHRONIZED
。有這種標識的,會被JVM要求執行方法之前先獲取到鎖,否則等待阻塞。
2.3 synchronized用於靜態方法或類物件
這種情況的ObjectMonitor就是該Class物件。
2.4 ObjectMonitor
每個物件都有一個物件監視器。
Object-Monitor在HotSpot中實現主要在
/Users/chengc/cc/work/projects/jdk8/hotspot/src/share/vm/runtime/objectMonitor.hpp
/Users/chengc/cc/work/projects/jdk8/hotspot/src/share/vm/runtime/objectMonitor.cpp
這裡摘錄一些重要的部分:
ObjectMonitor() {
_header = NULL;
_count = 0;
_waiters = 0,
_recursions = 0;
_object = NULL;
_owner = NULL;
_WaitSet = NULL;
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ;
FreeNext = NULL ;
_EntryList = NULL ;
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
_previous_owner_tid = 0;
}
注意_WaitSet
t和_EntryList
,他們被用來儲存該Object的等待物件的集合,具體來說:
_count
記錄已獲取鎖的次數_WaitSet
存放處於wait狀態的執行緒_EntryList
存放那些等待synchronized
同步鎖的執行緒_owner
是指向獲得了該物件的Monitor
許可權的執行緒的指標。_WaitSetLock
用來對WaitSet進行同步保護
他們的關係示意圖如下:
- 執行
synchronized
,進入EntrySet
,執行緒處於等待狀態 - 每次都只能有一個執行緒獲取到
ObjectMonitor
,_owner
指向該執行緒,處於Active
狀態。同時,將monitor計數器加1(退出一個同步塊時,monitor計數器減1) - 執行
wait
方法,會釋放ObjectMonitor,進入WaitSet
,執行緒處於等待狀態。同時,_owner
置為空,monitor計數器歸0。 - 執行當擁有ObjectMonitor許可權的執行緒釋放後會,如果呼叫了notify或notifyAll方法,會喚醒WaitSet中的執行緒。被喚醒的執行緒重新競爭同步鎖。
- 當退出
synchronized
塊後,完全釋放ObjectMonitor
2.5 ObjectWaiter
而EntryList和WaitSet中的等待物件ObjectWaiter
實現如下:
class ObjectWaiter : public StackObj {
public:
enum TStates { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER, TS_CXQ } ;
enum Sorted { PREPEND, APPEND, SORTED } ;
ObjectWaiter * volatile _next;
ObjectWaiter * volatile _prev;
Thread* _thread;
jlong _notifier_tid;
ParkEvent * _event;
volatile int _notified ;
volatile TStates TState ;
Sorted _Sorted ; // List placement disposition
bool _active ; // Contention monitoring is enabled
public:
ObjectWaiter(Thread* thread);
void wait_reenter_begin(ObjectMonitor *mon);
void wait_reenter_end(ObjectMonitor *mon);
};
- TStates
存放當前執行緒狀態 - _next和_prev
可以看到該物件有兩個分別指向前一個元素和後一個元素的指標,也就是說是一個雙向連結串列。 - _thread
指向的執行緒
2.6 monitorenter原始碼分析
2.6.1 位元組碼直譯器與模板直譯器
HotSpot程式碼中有兩個直譯器來解析jvm指令。前者是用C++實現每條JVM指令,但執行較慢。程式碼在jdk8/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
;後者(可參考這篇文章:JVM之模板直譯器)對每個指令都寫了一段彙編,啟動時指令與彙編繫結,效率很高。程式碼在jdk8/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp
但在HotSpot中只用了模板直譯器,所以我們直接看templateTable_x86_64.cpp
,我們要看的monitorenter
和monitorexit
方法就在這裡定義。
2.6.2 TemplateTable::monitorenter
2.6.1 InterpreterRuntime::monitorenter
對應到jdk8/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp
繼續看看monitorenter
方法實現,這裡摘錄部分對我們分析有意義的程式碼如下:
IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem))
// 這個h_obj封裝了該執行緒和擁有鎖的物件
Handle h_obj(thread, elem->obj());
if (UseBiasedLocking) {
// 當開啟了偏向鎖模式時,就優先使用快速進入模式避免不必要的鎖膨脹
ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK);
} else {
ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
}
2.6.2 BasicObjectLock
上面的monitorenter方法有兩個引數:
- thread:
JavaThread* thread:指向我們當前的執行緒 - BasicObjectLock* elem:
找到BasicObjectLock
位於jdk8/hotspot/src/share/vm/runtime/basicLock.hpp
:
// 一個BasicObjectLock將一個特定的Java物件與一個BasicLock相關聯,
// 它目前被嵌入到直譯器框架中。
class BasicObjectLock VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
private:
// 鎖物件,必須雙字(一般一個字是4位元組)對齊
BasicLock _lock;
// 持有該鎖的物件
oop _obj;
- 繼續看
BasicLock
,摘錄部分程式碼如下:
class BasicLock VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
private:
// 該私有變數_displaced_header就是用來描述物件頭資訊的
volatile markOop _displaced_header;
public:
markOop displaced_header() const { return _displaced_header; }
// 儲存物件頭的方法
void set_displaced_header(markOop header) { _displaced_header = header; }
}
2.6.3 鎖升級
注意前面我們提到的monitorenter
方法中核心程式碼:
if (UseBiasedLocking) {
// 當開啟了偏向鎖模式時,就優先使用快速進入模式避免不必要的鎖膨脹
ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK);
} else {
ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
}
也就是說,從這裡開始,我們的synchronized就要從偏向鎖開啟鎖升級之旅(前提是開啟了偏向鎖設定,否則從輕量級鎖開始)。
2.7 偏向鎖
2.7.1 偏向鎖的獲取
2.7.1.1 fast_enter
// 快速獲取/釋放monitor所有權
// 該方法在競爭場景下十分敏感
void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) {
// 判斷是否使用偏向鎖
if (UseBiasedLocking) {
if (!SafepointSynchronize::is_at_safepoint()) {
// 不在安全點,呼叫revoke_and_rebias方法獲取偏向鎖
BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD);
if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) {
return;
}
} else {
// 處於安全點,呼叫revoke_at_safepoint釋放偏向鎖
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輕量級鎖
slow_enter (obj, lock, THREAD) ;
}
2.7.1.2 biasedLocking.revoke_and_rebias
revoke_and_rebias
方法程式碼位於jdk8/hotspot/src/share/vm/runtime/biasedLocking.cpp
,主要做的就是獲取偏向鎖。確實因為能力有限看不懂了 - - 。這裡轉載佔小狼大神JVM原始碼分析之synchronized實現一文對該過程的描述,略有改動:
- 通過
markOop mark = obj->mark()
獲取物件的物件頭的Mark Word
; - 判斷
mark
是否為可偏向狀態,即mark的偏向鎖標誌位為 1且鎖標誌位為 01; - 判斷
mark
中JavaThread
指標的狀態:- 如果為空,則進入步驟(4);
- 如果指向當前執行緒,則執行同步程式碼塊;
- 如果指向其它執行緒,進入步驟(5);
- 通過CAS原子指令設定mark中的JavaThread為當前執行緒ID。如果執行CAS成功,則執行同步程式碼塊,否則進入步驟(5);
- 如果執行CAS失敗,表示當前存在多個執行緒競爭鎖。當達到全域性安全點(safepoint),獲得偏向鎖的執行緒被掛起,撤銷偏向鎖,並升級為輕量級鎖。升級完成後被阻塞在安全點的執行緒繼續執行同步程式碼塊。
2.7.2 偏向鎖的釋放
前面提到過,當已經位於安全點(is_at_safepoint),才可以釋放偏向鎖。
2.7.2.1 BiasedLocking::revoke_at_safepoint
void BiasedLocking::revoke_at_safepoint(Handle h_obj) {
//又一次斷言,只允許在安全點呼叫該方法
assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint");
// 封裝了執行緒和鎖物件
oop obj = h_obj();
// 這一步作用是更新釋放偏向鎖的計數
HeuristicsResult heuristics = update_heuristics(obj, false);
if (heuristics == HR_SINGLE_REVOKE) {
// 單撤銷模式
revoke_bias(obj, false, false, NULL);
} else if ((heuristics == HR_BULK_REBIAS) ||
(heuristics == HR_BULK_REVOKE)) {
// 批量撤銷模式(因為heuristics == HR_BULK_REBIAS為false)
bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL);
}
// 遍歷執行緒列表,清除所有monitor鎖快取資訊
clean_up_cached_monitor_info();
}
2.7.2.2 BiasedLocking::Condition revoke_bias
核心程式碼如下:
// 引數1為鎖物件和執行緒組合
// 引數2為是否允許偏向
// 引數3為是否批量模式
// 引數4申請執行緒
static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_bulk, JavaThread* requesting_thread) {
markOop mark = obj->mark();
if (!mark->has_bias_pattern()) {
// 非偏向鎖模式直接返回無偏向
return BiasedLocking::NOT_BIASED;
}
uint age = mark->age();
// 該值代表MarkWord最後3bit101
markOop biased_prototype = markOopDesc::biased_locking_prototype()->set_age(age);
// 該值代表MarkWord最後3bit001
markOop unbiased_prototype = markOopDesc::prototype()->set_age(age);
// 擁有偏向鎖的執行緒
JavaThread* biased_thread = mark->biased_locker();
if (biased_thread == NULL) {
// 此時偏向鎖沒有指向任何執行緒,可能是hashcode誤差等原因
if (!allow_rebias) {
// 不允許偏向,就設MarkWord為非偏向模式(無鎖,倒數第三bit設為0,最後2bit 01)
obj->set_mark(unbiased_prototype);
}
// 返回已撤銷偏向鎖
return BiasedLocking::BIAS_REVOKED;
}
bool thread_is_alive = false;
if (requesting_thread == biased_thread) {
// 看當前申請偏向鎖執行緒是否就是擁有偏向鎖的執行緒
thread_is_alive = true;
} else {
// 單撤銷偏向鎖的時候,requesting_thread為null
// 就遍歷所有執行緒
for (JavaThread* cur_thread = Threads::first(); cur_thread != NULL; cur_thread = cur_thread->next()) {
if (cur_thread == biased_thread) {
// 找到了擁有偏向鎖的執行緒,跳出迴圈
thread_is_alive = true;
break;
}
}
}
if (!thread_is_alive) {
// 擁有偏向鎖的執行緒已經掛了
if (allow_rebias) {
// 允許申請,就直接設為匿名可偏向模式,即MarkWord中執行緒id設為null,最後2bit 01
obj->set_mark(biased_prototype);
} else {
// 否則設為非偏向模式(無鎖,倒數第三bit設為0,最後2bit 01)
obj->set_mark(unbiased_prototype);
}
// 返回偏向鎖已經撤銷
return BiasedLocking::BIAS_REVOKED;
}
// 來到這裡,說明擁有偏向鎖的執行緒還活著
// 後面一系列程式碼做的事
// 先檢查該執行緒是否擁有monitor,如果是就將所需的`displaced headers`寫入執行緒的棧中
// 否則恢復鎖物件的頭資訊為
if (allow_rebias) {
// 設定為匿名偏向狀態
obj->set_mark(biased_prototype);
} else {
// 設為無鎖
obj->set_mark(unbiased_prototype);
}
// 最後返回鎖已經撤銷
return BiasedLocking::BIAS_REVOKED;
}
2.8 輕量級鎖
2.8.1 slow_enter-獲取鎖
摘錄核心程式碼如下:
void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
// 獲取物件頭的MarkWord部分
markOop mark = obj->mark();
// 此時不應該是偏向鎖模式
assert(!mark->has_bias_pattern(), "should not see bias pattern here");
if (mark->is_neutral()) {
// is_neutral代表無鎖
// Anticipate successful CAS -- the ST of the displaced mark must
// be visible <= the ST performed by the CAS.
// lock儲存該物件頭的MarkWord
lock->set_displaced_header(mark);
// CAS方式將目標物件的MarkWord替換為lock
if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) {
// CAS方式成功,代表該執行緒成功獲取鎖,可以返回執行同步塊程式碼了
TEVENT (slow_enter: release stacklock) ;
return ;
}
// Fall through to inflate() ...
} else
if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
// 此時MarkWord為輕量級鎖狀態,且該鎖擁有者就是當前Thread
// 此時就是輕量級鎖的重入情況,可以返回了
lock->set_displaced_header(NULL);
return;
}
// 搜了下,下面這段程式碼因為#if 0的,相當於註釋永不執行。。。
#if 0
// The following optimization isn't particularly useful.
if (mark->has_monitor() && mark->monitor()->is_entered(THREAD)) {
lock->set_displaced_header (NULL) ;
return ;
}
#endif
// The object header will never be displaced to this lock,
// so it does not matter what the value is, except that it
// must be non-zero to avoid looking like a re-entrant lock,
// and must not look locked either.
lock->set_displaced_header(markOopDesc::unused_mark());
// 到了這裡,說明輕量級鎖存在競爭,需要膨脹為重量級鎖
ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
}
2.8.2 slow_exit-釋放鎖1
void ObjectSynchronizer::slow_exit(oop object, BasicLock* lock, TRAPS) {
fast_exit (object, lock, THREAD) ;
}
2.8.3 fast_exit-釋放鎖2
摘錄核心程式碼如下:
void ObjectSynchronizer::fast_exit(oop object, BasicLock* lock, TRAPS) {
// dhw指向MarkWord副本
markOop dhw = lock->displaced_header();
markOop mark ;
// mark指向真實MarkWord
mark = object->mark() ;
if (mark == (markOop) lock) {
assert (dhw->is_neutral(), "invariant") ;
// 如果當前執行緒擁有鎖,就CAS方式還原MarkWord
if ((markOop) Atomic::cmpxchg_ptr (dhw, object->mark_addr(), mark) == mark) {
TEVENT (fast_exit: release stacklock) ;
return;
}
}
// CAS失敗,說明其他執行緒嘗試過獲取該鎖。
// 此時不僅要釋放鎖,還需要膨脹為重量級鎖
ObjectSynchronizer::inflate(THREAD, object)->exit (true, THREAD) ;
}
2.9 重量級鎖-膨脹
實現主要在以下方法中:
ObjectMonitor * ATTR ObjectSynchronizer::inflate (Thread * Self, oop object)
關於重量級鎖的膨脹、鎖enter/exit等細節待補充,可以參見佔小狼的JVM原始碼分析之synchronized實現。
2.10 monitorexit原始碼分析
2.10.1 InterpreterRuntime::monitorexit
核心程式碼如下:
IRT_ENTRY_NO_ASYNC
相關推薦
Java-併發-鎖-synchronized
Java-併發-鎖-synchronized
摘要
本文會詳細說下synchronized的底層實現原理。
0x01 基本概念
每次只能有一個執行緒進入臨界區
保證臨界區內共享變數的可見性和有序性
成功進入synchronized區域的執行緒可以拿到物
【Java併發】synchronized之偏向鎖和輕量級鎖
synchronized之偏向鎖和輕量級鎖
上下文切換
synchronized
鎖的升級與對比
偏向鎖
輕量級鎖
參考
上下文切換
即使是單核處理器也支援多執行緒執行程式碼執行程式碼,CPU通
JAVA併發鎖 - 悲觀鎖VS樂觀鎖(一)
文章目錄
悲觀鎖VS樂觀鎖
1.悲觀鎖
1.1什麼是悲觀鎖
1.2原始碼分析
synchronized
Lock
1.3應用場景
1.4實現
java併發之----synchronized與ReenTrantLock
Java 提供了兩種鎖機制來控制多個執行緒對共享資源的互斥訪問,第一個是 JVM 實現的 synchronized,而另一個是 JDK 實現的 ReentrantLock。
synchronized
synchronized關鍵字最主要幾種使用方式: (1)同步一個程式碼塊: 只作用
Java-併發-鎖-LockSupport
Java-併發-鎖-LockSupport
0x01 摘要
LockSupport是用來建立鎖和其他同步類的基本執行緒阻塞原語,他的兩個主要方法park()和 unpark()的作用分別是阻塞執行緒和解除阻塞執行緒。本文簡要分析下他的原始碼。
0x02 原始碼解析
2.1
深入理解Java併發之synchronized實現原理
關聯文章:
本篇主要是對Java併發中synchronized關鍵字進行較為深入的探索,這些知識點結合博主對synchronized的個人理解以及相關的書籍的講解(在結尾參考資料),如有誤處,歡迎留言。
執行緒安全是併發程式
JAVA互斥鎖(synchronized&Lock):行為分析及原始碼
JVM中有這樣一段註釋:
// The base-class, PlatformEvent, is platform-specific while the ParkEvent is
// platform-independent. PlatformEvent provides park()
Java併發——鎖框架(三)讀寫鎖
1. 讀寫鎖機制——ReadWriteLock介面
讀寫鎖適用於對資料結構頻繁讀而較少修改的場景。舉個栗子,你可以建立一個線上詞典供多條讀執行緒併發讀取,然而單條寫執行緒可能會不時新增新的定義或更新已有的定義。一個資源可以被多個執行緒同時讀,或者被一個執行緒寫,但是不能同時存在讀和寫執行緒。&n
Java併發——鎖框架(二)重入鎖ReentrantLock
1. 重入鎖
重入鎖,顧名思義,就是支援重進入的鎖,它表示該鎖能夠支援一個執行緒對資源的重複加鎖。重進入是指任意執行緒在獲取到鎖之後能夠再次獲取該鎖而不會被鎖阻塞。兩個關鍵問題:
(1)執行緒再次獲取鎖。當一條執行緒持有這個鎖並且呼叫lock()、lockUninterruptibly()或
Java併發——鎖框架(一)
來源:《Java執行緒與併發程式設計實踐》以及
https://blog.csdn.net/qq_38293564/article/details/80476659
1. 鎖框架
java.util.co
(七)java併發程式設計synchronized+volatile(安全初始化模式例項)
安全釋出物件的安全性都來自於JMM提供的保證,而造成不正確的釋出原因,就是在”釋出一個共享物件”與”另一個執行緒訪問該物件”之間缺少一種Happen-Before排序.
不安全的釋出
package safe_unsafe_public
(六)java併發程式設計--synchronized同步塊
雖然前面文章的一些例項中已經使用synchronized關鍵字來實現執行緒的同步,但還是需要好好的理解一下。
一段程式碼或者一個方法被synchronized關鍵字標記我們就說這斷程式碼是同步塊。同步塊可以用來避免競爭條件。
synchronize
[Java]同步鎖synchronized
在多執行緒操作資料時需要考慮使用synchronized關鍵詞修飾屬性或方法,同步鎖synchronized大致可分為兩類:物件鎖、全域性鎖。在分析同步鎖程式碼時需要關心兩個問題:鎖的物件是誰、誰持有鎖。
①物件鎖:
當一個執行緒訪問物件object的一個synchronized(thi
Java-併發-鎖-ReentrantLock
Java-併發-鎖-ReentrantLock
摘要
ReentrantLock是使用最廣的、最出名的AQS(AbstractQueuedSynchronizer)系列的可重入鎖。本文會分析他的lock, unlock等重要方法,還涉及公平/非公平概念對比,及對比synchron
java併發程式設計---synchronized關鍵字
在併發程式設計中,多執行緒同時併發訪問的資源叫做臨界資源,當多個執行緒同時訪問物件並要求操作相同資源時,分割了原子操作就有可能出現數據的不一致或資料不完整的情況,為避免這種情況的發生,我們會採取同步機制,以確保在某一時刻,方法內只允許有一個執行緒。
採用syn
《大話設計模式》讀書筆記:單例模式與Java同步鎖synchronized
單例模式,保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。在單例模式下,類本身負責儲存它的唯一例項,這個類必須保證沒有其他例項可以被建立,並且它可以提供一個訪問該例項的方法。單例模式的類中,構造方法(函式/體)被設為private,從而堵死了外部例項化該類的可能。同
Java併發控制synchronized與AtomicInteger類
眾所周知,在Java多執行緒程式設計中,一個非常重要的方面就是執行緒的同步問題。關於執行緒的同步,最常用的解決方法就是使用synchronized關鍵字,但是如果使用場景只用在控制一個計數的整型變數時
原始碼閱讀:Java併發之synchronized實現原理
執行緒安全是併發程式設計中的重要關注點,應該注意到的是,造成執行緒安全問題的主要誘因有兩點,一是存在共享資料(也稱臨界資源),二是存在多條執行緒共同操作共享資料。因此為了解決這個問題,我們可能需要這樣一個方案,當存在多個執行緒操作共享資料時,需要保證同一時刻有且
深入理解 Java 併發之 synchronized 實現原理
關聯文章深入理解Java型別資訊(Class物件)與反射機制深入理解Java列舉型別(enum)深入理解Java註解型別(@Annotation)深入理解Java併發之synchronized實現原理本篇主要是對Java併發中synchronized關鍵字進行較為深入的探索,這些知識點結合博主對synchro
java 併發之 synchronized 實現原理
在 java 開發中 synchronized 是使用的最多的工具。
表現形式
在 java 中每個物件都可以作為鎖:
對於普通同步方法,鎖是當前例項物件;
對於靜態同步方法,鎖是當前類的 Class 物件;
對於同步方法快,鎖是 Synchronized 括