關於多個執行緒同時呼叫單例模式的物件,該物件中方法的區域性變數是否會受多個執行緒的影響
關於多個執行緒同時呼叫單例模式的物件,該物件中方法的區域性變數是否會受多個執行緒的影響
對於那些會以多執行緒執行的單例類,例如Web應用中的Servlet,每個方法中對區域性變數的操作都是線上程自己獨立的記憶體區域內完成的,所以是執行緒安全的。
對於成員變數的操作,可以使用ThreadLocal來保證執行緒安全。
區域性變數不會受多執行緒影響
成員變數會受到多執行緒影響
多個執行緒應該是呼叫的同一個物件的同一個方法:
如果方法裡無成員變數,那麼不受任何影響
如果方法裡有成員變數,只有讀操作,不受影響
存在寫操作,考慮多執行緒影響值
深入Java核心:JVM中的棧和區域性變數
在Java程式中,每當啟用一個執行緒時,JVM就為他分配一個Java棧,棧是以幀為單位儲存當前執行緒的執行狀態。今天我們繼續深入Java核心,探祕JVM中的棧和區域性變數。
Java開發中,每當我們在程式中使用new生成一個物件,物件的引用存放在棧裡,而物件是存放在堆裡的。可以看出棧在Java核心的重要位置。今天我們就繼續深入Java核心這個系列,為您介紹Java中的棧、區域性變數及其之間的關係。
深入Java核心:Java記憶體分配原理精講 探祕Java垃圾回收機制 Java中多型的實現機制
Java中的棧
每當啟用一個執行緒時,JVM就為他分配一個Java棧,棧是以幀為單位儲存當前執行緒的執行狀態。某個執行緒正在執行的方法稱為當前方法,當前方法使用的棧幀稱為當前幀,當前方法所屬的類稱為當前類,當前類的常量池稱為當前常量池。當執行緒執行一個方法時,它會跟蹤當前常量池。
每當執行緒呼叫一個Java方法時,JVM就會在該執行緒對應的棧中壓入一個幀,這個幀自然就成了當前幀。當執行這個方法時,它使用這個幀來儲存引數、區域性變數、中間運算結果等等。
Java棧上的所有資料都是私有的。任何執行緒都不能訪問另一個執行緒的棧資料。所以我們不用考慮多執行緒情況下棧資料訪問同步的情況。
像方法區和堆一樣,Java棧和幀在記憶體中也不必是連續的,幀可以分佈在連續的棧裡,也可以分佈在堆裡
Java棧的組成元素——棧幀
棧幀由三部分組成:區域性變數區、運算元棧、幀資料區。區域性變數區和運算元棧的大小要視對應的方法而定,他們是按字長計算的。但呼叫一個方法時,它從型別資訊中得到此方法區域性變數區和運算元棧大小,並據此分配棧記憶體,然後壓入Java棧。
區域性變數區 區域性變數區被組織為以一個字長為單位、從0開始計數的陣列,型別為short、byte和char的值在存入陣列前要被轉換成int值,而long和 double在陣列中佔據連續的兩項,在訪問區域性變數中的long或double時,只需取出連續兩項的第一項的索引值即可,如某個long值在區域性變數區中佔據的索引時3、4項,取值時,指令只需取索引為3的long值即可。
下面就看個例子,好讓大家對區域性變數區有更深刻的認識。這個圖來自《深入JVM》:
上面程式碼片的方法引數和區域性變數在區域性變數區中的儲存結構如下圖:
上面這個圖沒什麼好說的,大家看看就會懂。但是,在這個圖裡,有一點需要注意:
runInstanceMethod的區域性變數區第一項是個reference(引用),它指定的就是物件本身的引用,也就是我們常用的this,但是在runClassMethod方法中,沒這個引用,那是因為runClassMethod是個靜態方法。
運算元棧和區域性變數區一樣,運算元棧也被組織成一個以字長為單位的陣列。但和前者不同的是,它不是通過索引來訪問的,而是通過入棧和出棧來訪問的。可把運算元棧理解為儲存計算時,臨時資料的儲存區域。下面我們通過一段簡短的程式片段外加一幅圖片來了解下運算元棧的作用。
int a = 100;
int b = 98;
int c = a+b;
從圖中可以得出:運算元棧其實就是個臨時資料儲存區域,它是通過入棧和出棧來進行操作的。
幀資料區除了區域性變數區和運算元棧外,Java棧幀還需要一些資料來支援常量池解析、正常方法返回以及異常派發機制。這些資料都儲存在Java棧幀的幀資料區中。
當JVM執行到需要常量池資料的指令時,它都會通過幀資料區中指向常量池的指標來訪問它。
除了處理常量池解析外,幀裡的資料還要處理Java方法的正常結束和異常終止。如果是通過return正常結束,則當前棧幀從Java棧中彈出,恢復發起呼叫的方法的棧。如果方法又返回值,JVM會把返回值壓入到發起呼叫方法的運算元棧。
為了處理Java方法中的異常情況,幀資料區還必須儲存一個對此方法異常引用表的引用。當異常丟擲時,JVM給catch塊中的程式碼。如果沒發現,方法立即終止,然後JVM用幀區資料的資訊恢復發起呼叫的方法的幀。然後再發起呼叫方法的上下文重新丟擲同樣的異常。
棧的整個結構
在前面就描述過:棧是由棧幀組成,每當執行緒呼叫一個Java方法時,JVM就會在該執行緒對應的棧中壓入一個幀,而幀是由區域性變數區、運算元棧和幀資料區組成。那在一個程式碼塊中,棧到底是什麼形式呢?下面是我從《深入JVM》中摘抄的一個例子,大家可以看看:
程式碼片段:
執行過程中的三個快照:
上面所給的圖,只想說明兩件事情,我們也可用此來理解Java中的棧:
1、只有在呼叫一個方法時,才為當前棧分配一個幀,然後將該幀壓入棧。
2、幀中儲存了對應方法的區域性資料,方法執行完,對應的幀則從棧中彈出,並把返回結果儲存在呼叫方法的幀的運算元棧中。
對於那些會以多執行緒執行的單例類,例如Web應用中的Servlet,每個方法中對區域性變數的操作都是線上程自己獨立的記憶體區域內完成的,所以是執行緒安全的。
對於成員變數的操作,可以使用ThreadLocal來保證執行緒安全。
區域性變數不會受多執行緒影響
成員變數會受到多執行緒影響
多個執行緒應該是呼叫的同一個物件的同一個方法:
如果方法裡無成員變數,那麼不受任何影響
如果方法裡有成員變數,只有讀操作,不受影響
存在寫操作,考慮多執行緒影響值
深入Java核心:JVM中的棧和區域性變數
在Java程式中,每當啟用一個執行緒時,JVM就為他分配一個Java棧,棧是以幀為單位儲存當前執行緒的執行狀態。今天我們繼續深入Java核心,探祕JVM中的棧和區域性變數。
Java開發中,每當我們在程式中使用new生成一個物件,物件的引用存放在棧裡,而物件是存放在堆裡的。可以看出棧在Java核心的重要位置。今天我們就繼續深入Java核心這個系列,為您介紹Java中的棧、區域性變數及其之間的關係。
深入Java核心:Java記憶體分配原理精講 探祕Java垃圾回收機制 Java中多型的實現機制
Java中的棧
每當啟用一個執行緒時,JVM就為他分配一個Java棧,棧是以幀為單位儲存當前執行緒的執行狀態。某個執行緒正在執行的方法稱為當前方法,當前方法使用的棧幀稱為當前幀,當前方法所屬的類稱為當前類,當前類的常量池稱為當前常量池。當執行緒執行一個方法時,它會跟蹤當前常量池。
每當執行緒呼叫一個Java方法時,JVM就會在該執行緒對應的棧中壓入一個幀,這個幀自然就成了當前幀。當執行這個方法時,它使用這個幀來儲存引數、區域性變數、中間運算結果等等。
Java棧上的所有資料都是私有的。任何執行緒都不能訪問另一個執行緒的棧資料。所以我們不用考慮多執行緒情況下棧資料訪問同步的情況。
像方法區和堆一樣,Java棧和幀在記憶體中也不必是連續的,幀可以分佈在連續的棧裡,也可以分佈在堆裡
Java棧的組成元素——棧幀
棧幀由三部分組成:區域性變數區、運算元棧、幀資料區。區域性變數區和運算元棧的大小要視對應的方法而定,他們是按字長計算的。但呼叫一個方法時,它從型別資訊中得到此方法區域性變數區和運算元棧大小,並據此分配棧記憶體,然後壓入Java棧。
區域性變數區 區域性變數區被組織為以一個字長為單位、從0開始計數的陣列,型別為short、byte和char的值在存入陣列前要被轉換成int值,而long和 double在陣列中佔據連續的兩項,在訪問區域性變數中的long或double時,只需取出連續兩項的第一項的索引值即可,如某個long值在區域性變數區中佔據的索引時3、4項,取值時,指令只需取索引為3的long值即可。
下面就看個例子,好讓大家對區域性變數區有更深刻的認識。這個圖來自《深入JVM》:
public static int runClassMethod(int i,long l,float f,double d,Object o,byte b) {
return 0;
}
public int runInstanceMethod(char c,double d,short s,boolean b) {
return 0;
}
上面程式碼片的方法引數和區域性變數在區域性變數區中的儲存結構如下圖:
上面這個圖沒什麼好說的,大家看看就會懂。但是,在這個圖裡,有一點需要注意:
runInstanceMethod的區域性變數區第一項是個reference(引用),它指定的就是物件本身的引用,也就是我們常用的this,但是在runClassMethod方法中,沒這個引用,那是因為runClassMethod是個靜態方法。
運算元棧和區域性變數區一樣,運算元棧也被組織成一個以字長為單位的陣列。但和前者不同的是,它不是通過索引來訪問的,而是通過入棧和出棧來訪問的。可把運算元棧理解為儲存計算時,臨時資料的儲存區域。下面我們通過一段簡短的程式片段外加一幅圖片來了解下運算元棧的作用。
int a = 100;
int b = 98;
int c = a+b;
從圖中可以得出:運算元棧其實就是個臨時資料儲存區域,它是通過入棧和出棧來進行操作的。
幀資料區除了區域性變數區和運算元棧外,Java棧幀還需要一些資料來支援常量池解析、正常方法返回以及異常派發機制。這些資料都儲存在Java棧幀的幀資料區中。
當JVM執行到需要常量池資料的指令時,它都會通過幀資料區中指向常量池的指標來訪問它。
除了處理常量池解析外,幀裡的資料還要處理Java方法的正常結束和異常終止。如果是通過return正常結束,則當前棧幀從Java棧中彈出,恢復發起呼叫的方法的棧。如果方法又返回值,JVM會把返回值壓入到發起呼叫方法的運算元棧。
為了處理Java方法中的異常情況,幀資料區還必須儲存一個對此方法異常引用表的引用。當異常丟擲時,JVM給catch塊中的程式碼。如果沒發現,方法立即終止,然後JVM用幀區資料的資訊恢復發起呼叫的方法的幀。然後再發起呼叫方法的上下文重新丟擲同樣的異常。
棧的整個結構
在前面就描述過:棧是由棧幀組成,每當執行緒呼叫一個Java方法時,JVM就會在該執行緒對應的棧中壓入一個幀,而幀是由區域性變數區、運算元棧和幀資料區組成。那在一個程式碼塊中,棧到底是什麼形式呢?下面是我從《深入JVM》中摘抄的一個例子,大家可以看看:
程式碼片段:
執行過程中的三個快照:
上面所給的圖,只想說明兩件事情,我們也可用此來理解Java中的棧:
1、只有在呼叫一個方法時,才為當前棧分配一個幀,然後將該幀壓入棧。
2、幀中儲存了對應方法的區域性資料,方法執行完,對應的幀則從棧中彈出,並把返回結果儲存在呼叫方法的幀的運算元棧中。
相關文章
- 多執行緒中,區域性變數與全域性變數哪個比較安全?執行緒變數
- 物件中的靜態屬性是否在多執行緒中共享物件執行緒
- 如何產生一個C++區域性靜態物件的多執行緒問題C++物件執行緒
- Java中一個物件在多執行緒中是共享的Java物件執行緒
- 多執行緒,到底該設定多少個執行緒?執行緒
- Java多執行緒——獲取多個執行緒任務執行完的時間Java執行緒
- 多執行緒下的單例執行緒單例
- 單執行緒的JS如何實現多個互動同時進行執行緒JS
- 24. 一個普通main方法的執行,是單執行緒模式還是多執行緒模式?為什麼?AI執行緒模式
- JAVA_多執行緒_單例模式Java執行緒單例模式
- 多執行緒(五)---執行緒的Yield方法執行緒
- 同時多個SQL命令執行的方法SQL
- 請教一個涉及到多執行緒的關於單例的問題執行緒單例
- 單例避免多執行緒同時修改同個值從而造成髒資料單例執行緒
- 多執行緒統計多個檔案的單詞數目---C++0x多執行緒使用示例執行緒C++
- 多執行緒(2)-執行緒同步條件變數執行緒變數
- C#中的執行緒(三)多執行緒C#執行緒
- 有個關於多執行緒的識別問題執行緒
- 關於c#多執行緒中的幾個訊號量C#執行緒
- 4核8執行緒和6核6執行緒的CPU哪個好?電腦CPU核數多和執行緒多的區別執行緒
- Qt中的多執行緒與執行緒池淺析+例項QT執行緒
- 多執行緒-獲取和設定執行緒物件名稱執行緒物件
- 關於多執行緒控制執行緒
- 關於多執行緒(轉)執行緒
- 多執行緒中的使用共享變數的問題執行緒變數
- 執行緒以及多執行緒,多程式的選擇執行緒
- 多執行緒-多執行緒常見的面試題執行緒面試題
- 多執行緒Demo學習(執行緒的同步,簡單的執行緒通訊)執行緒
- Java多執行緒/併發12、多執行緒訪問static變數Java執行緒變數
- Java中的多執行緒Java執行緒
- RxJava 中的多執行緒RxJava執行緒
- Qt 中的多執行緒QT執行緒
- 多執行緒中的ManualResetEvent執行緒
- python多執行緒中:如何關閉執行緒?Python執行緒
- 【java】【多執行緒】獲取和設定執行緒名字、獲取執行緒物件(3)Java執行緒物件
- Java執行緒面試題(01) Java中如何檢查一個執行緒是否擁特定物件的鎖Java執行緒面試題物件
- C++ 靜態變數單例模式的誤會(執行緒安全)C++變數單例模式執行緒
- 關於Python多執行緒的理解Python執行緒