簡體   English   中英

線程安全和局部變量

[英]Thread safety and local variables

如果我有一個像這樣的局部變量:

Increment()
{
    int i = getFromDb(); // get count for a customer from db 
};

這是一個實例 class 遞增(每次客戶 - 實例 object - 進行購買),這個變量線程安全嗎? 我聽說局部變量是線程安全的,因為每個線程都有自己的堆棧等。

另外,我認為這個變量是共享的 state 是否正確? 我在思考方面缺乏的是這個變量將與不同的客戶對象(例如 John、Paul 等)一起工作,因此是線程安全的,但這是有缺陷的思考,並且在並發編程方面有點缺乏經驗。 這聽起來很天真,但是我在並發編碼方面沒有很多經驗,就像我通常做的同步編碼一樣。

編輯:此外,function 調用 getFromDb() 不是問題的一部分,我不希望任何人猜測它的線程安全性,因為它只是一個調用,表明該值是從從數據庫獲取數據的 function 分配的. :)

編輯 2:此外,getFromDb 的線程安全得到保證,因為它只執行讀取操作。

i被聲明為本地(方法)變量,所以它通常只存在於Increment()的堆棧幀中 - 所以是的, i是線程安全的......(雖然我不能評論getFromDb )。

除非

  • Increment是一個迭代器塊(即使用yield returnyield break
  • i用於匿名方法 ( delegate { i = i + 1;} ) 或 lambda ( foo => {i=i+foo;}

在上述兩種場景中,有一些情況是可以暴露在棧外的。 但我懷疑你是否也在這樣做。

請注意,字段(類上的變量)不是線程安全的,因為它們很容易暴露給其他線程。 這在static字段中更加明顯,因為所有線程自動共享相同的字段(線程靜態字段除外)。

您的語句有兩個單獨的部分 - 一個 function 調用和一個賦值。

賦值是線程安全的,因為變量是本地的。 對該方法的每次不同調用都會獲得自己的局部變量版本,每個變量都存儲在 memory 中不同位置的不同堆棧幀中。

對 getFromDb() 的調用可能是線程安全的,也可能不是線程安全的——取決於它的實現。

只要變量是方法的本地變量,它就是線程安全的。 如果它是 static 變量,則默認情況下不會。

class Example
{
  static int var1; //not thread-safe

  public void Method1()
   { int var2; //thread-safe
   }
}

雖然您的 int i 是線程安全的,但您的整個案例可能不是線程安全的。 正如您所說,您的 int i 是線程安全的,因為每個線程都有自己的堆棧跟蹤,因此每個線程都有自己的 i。 但是,您的線程都共享同一個數據庫,因此您的數據庫訪問不是線程安全的。 您需要正確同步數據庫訪問,以確保每個線程僅在正確的時刻看到數據庫。

與通常的並發和多線程一樣,如果您只讀取信息,則不需要在數據庫上進行同步。 一旦兩個線程嘗試從您的數據庫中讀取/寫入同一組信息,您確實需要同步。

i 將是“線程安全的”,因為每個線程都會按照您的建議在堆棧上擁有自己的 i 副本。 真正的問題是 getFromDb() 線程的內容是否安全?

i 是一個局部變量,因此它不共享 state。

如果您的 getFromDb() 正在讀取 oracle 序列或 sql 服務器自動增量字段,那么數據庫正在處理同步(在大多數情況下,不包括復制/分布式數據庫),因此您可以安全地將結果返回給任何調用線。 也就是說,數據庫保證每個 getFromDB() 調用都會獲得不同的值。

線程安全通常需要做一些工作——更改變量的類型很少會為您帶來線程安全,因為它取決於您的線程將如何訪問數據。 您可以通過重新設計算法來省去一些麻煩,以便它使用所有消費者同步的隊列,而不是嘗試編排一系列鎖/監視器。 或者如果可能的話,最好讓算法無鎖。

i 在語法上是線程安全的。 但是當你給實例變量賦值時,實例方法的返回值給i,那么共享數據就會被多個線程操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM