靜態方法能被兩個方法同一時刻調用嗎?

我具體描述一下問題,就是一個靜態方法(只有一個實例),能在同一時刻接受兩個請求嗎?

再具體就是:會出現第一個請求訪問靜態方法執行到靜態方法內部第8行代碼;同時接受第二個訪問請求,執行到靜態方法第2行代碼。會出現這種情況嗎?

如果出現這種情況就要考慮方法所操作的變數出現數據損壞的情況,平時寫代碼為什麼都不去考慮這種情況?

那同樣的,同一個實例的同一個方法是不是也會遇到同樣的情況?

========================================================

那lock機制是怎麼做到鎖資源的,怎麼做到讀鎖判斷然後在鎖資源,那麼這兩步的話同時被調用了怎麼辦?


&>我具體描述一下問題,就是一個靜態方法(只有一個實例),能在同一時刻接受兩個請求嗎?

能,但是靜態方法不是什麼只有一個實例 是沒有實例的方法

》再具體就是:會出現第一個請求訪問靜態方法執行到靜態方法內部第8行代碼;同時接受第二個訪問請求,執行到靜態方法第2行代碼。會出現這種情況嗎?

會,多線程環境下

》如果出現這種情況就要考慮方法所操作的變數出現數據損壞的情況,平時寫代碼為什麼都不去考慮這種情況?

每個線程會用獨立的棧控制項保存線程獨立的變數,至於你沒有提到的欄位和屬性,是需要設計鎖等方式來進行競爭處理(並發處理)

》那同樣的,同一個實例的同一個方法是不是也會遇到同樣的情況?


靜態方法和實例方法是沒有區別的,他們都是一段程序,即便是實例方法,也是有固定入口地址的一段程序,沒有「具有多個還是一個實例」這種概念。每次方法調用的時候,都具有獨立的活動記錄(也就是本地變數),正如你遞歸調用方法並不會抹掉上一級調用的本地變數。這種活動記錄一般是由棧來實現的 。至於多線程,重點問題在於有沒有訪問共享的資源,這個問題同樣並不區分是靜態還是實例方法,你只需要學習多線程一般的知識即可同時適用於任何方法。


多線程不就是這樣嗎,誰說平時寫代碼不考慮這個問題了。


我具體描述一下問題,就是一個靜態方法(只有一個實例),能在同一時刻接受兩個請求嗎?

---- 會

再具體就是:會出現第一個請求訪問靜態方法執行到靜態方法內部第8行代碼;同時接受第二個訪問請求,執行到靜態方法第2行代碼。會出現這種情況嗎?

----會

如果出現這種情況就要考慮方法所操作的變數出現數據損壞的情況,平時寫代碼為什麼都不去考慮這種情況?

----要考慮!

那同樣的,同一個實例的同一個方法是不是也會遇到同樣的情況?

---是

//-----------------------------------------------------

這個問題其實就是函數"不可重入"問題,另外雖然C++里靜態方法中沒有this指針但是

靜態方法可以調用static變數以及以static變數為基礎的單例及單例中存放的數據

,或者操作IO,或者一個static的全局鎖.

所以遇到不可重入函數自然是要小心,不光是多線程調用同一個函數的情況,即使是單線程也可能出問題,例如:

static LockType lock;

..................

bool callMeTwiceAndWaitToYouDie()
{
lock.enter();
.................
.................
if(xxxx) {
if(callMeTwiceAndWaitToYouDie()) return true;
}
.................
.................
.................
lock.exit();
return false;
}

即使是單線程,進了這個方法就等著去吧....

上面的例子很簡單,但是當邏輯越來越複雜,很可能即使單線程也可能真的有這種情況出現,

不然也不會出現Critical Section這種東西了.


  • 靜態方法和實例方法的區別是靜態方法只能引用靜態變數,靜態方法通過類名來調用,實例方法通過對象實例來調用

  • 每個線程都有自己的線程棧,棧與線程同時創建,每一個虛擬機線程都有自己的程序計數器PC,在任何時刻,一個虛擬機線程只會執行一個方法的代碼,這個方法稱為該線程的當前方法,如果這個方法不是native的,程序計數器就保存虛擬機正在執行的位元組碼指令的地址。
  • 線程調用方法的時候會創建棧幀,用於保存局部變數表和操作數棧以及指向該類常量池的引用
  • 你所說的第一個線程執行到方法的第8行,第二個線程執行到第二行,雖然是同一個方法,但是不同線程在調用,程序計數器的值是不一樣的,操作這兩個線程不會相互影響(假設不存在訪問共享變數的情況)


方法的局部變數在線程調用棧上,不共享,所以不用同步。類似工具類,任意線程任意調用。互不影響


多線程調用就會出現,解決方法是做線程同步處理。

呃,協程理論上也會,但是既然用到協程,就要自己考慮代碼執行的順序。

還有遞歸,明顯的遞歸一般會處理,但是有些是隱形的,譬如VB6的Doevents,MFC的PumpMessage等等都會導致不經意的函數重入。


可以,但是有bug


首先要搞清楚,靜態方法是不綁定實例的!更確切地講,方法與實例一直是分開的!!非靜態類成員方法通個編繹器幫忙傳this指針作第一個參數來綁定實例。

非靜態類成員方法也可以出現兩個線程正在同時調用。


線程安全關鍵不在方法是否靜態,而在資源是否競爭。。。


我之前也在這個地方糊塗了,現在大概想明白了,不知道說的對不對。

不管是單例還是多實例的方法,創建多個對象應該可以想像為多個指針和單個指針,而這個指針指向的區域不同的應該是實例所擁有的變數不同,對於方法,我猜測 java 應該不會把相同的方法複製好幾份來,也沒有必要,所以具體的方法應該指向的都是方法區裡面同一個方法。

不同線程調用的時候,方法棧應該也指向的是同一個方法,可能是不同的行,因為沒有了變數的方法執行的操作是無狀態的,而狀態是不同線程執行的時候帶進去的。

所以對於非單例類,方法應該是相同的,但是不同線程所持有的對象的實例裡面變數是不同的,他們拿著自己的實例去找方法執行,然後 CPU 分給誰了,就去執行指向的代碼,互不影響。

如果是單例,也是一樣,只不過沒有實例,所以不同線程就不可能有自己持有的對象了,這時候如果這個單例是有狀態的,方法是原子操作還好,非原子操作就會造成並發問題,一般可以用線程安全的編程方法來處理。


我自己寫程序驗證過,靜態方法的執行可以同一時間(極小時間段內)在不同的線程中運行


當然能啊


我記得JAVA下多線程執行靜態方法是不用鎖的,當然前提是沒有涉及到公共變數


題主你是博客園的吉日格拉么?


代碼段應該是同一進程下的線程共享的,CPU只管取值就行咯


可以。其實就是線程安全問題,如果只是一個工具方法用來處理傳進來的東西再返回出去,一般是不考慮線程安全的。如果說牽扯到公共數據的操作,如某些全局變數,操作資料庫等(只是舉個例子),就得考慮線程安全問題了。


靜態方法不是放在方法區中可以可以隨時被調用的么 不需要建立實例對象


之前我也想過這個問題。

方法說白了就是一個公式。誰都可以用公式。

靜態的方法只是調用方便,跟普通方法沒有區別。

如果難理解,你就理解成每次調用方法的時候都會生成新的方法實例(區別類實例),他們互不影響。


我覺得lock就是編譯器自己添加了一個全局變數來供線程判斷


推薦閱讀:

C++寫光柵化渲染器遇到些問題?
如何高效學習並掌握現代C++?
learn python the hard way 習題13運行問題..?
為什麼人們會崇拜一個編程語言?
程序猿怎樣才能修鍊到負責一個真正意義上的項目?

TAG:編程 | C編程語言 | C | C# | JavaEE |