你管這叫 "線程安全"?

今日份的乾糧:

  1. 什麼叫線程安全?2. 線程安全與變量的關係?• 變量又與堆 / 棧 / 靜態存儲區有密切關係

什麼叫線程安全?

我們以常見的一行代碼i++ ,i-- 爲例, 計算機的操作姿勢可能與你想象的不一樣。

在大多數計算機中, 給變量自增自減並不是原子操作, 需要下面三步:
① 將變量值加載進寄存器
② 寄存器自增 / 自減值
③ 將寄存器值加載回原變量

多線程環境下,如果你不使用一些原子鎖操作:
線程 A ( i++ ) 可能只執行了前面兩步後,之後 CPU 輪詢切換到其他線程或者線程 A 被搶佔 CPU;線程 B ( i-- ) 欻欻執行完所有的三步;

當線程 A 重新獲得 CPU,執行第三步, 一下子影響了線程 B 的執行預期。

上圖栩栩如生、動靜相宜地描述了 啥叫線程安全,這就是線程不安全! ☹️

你能遇到的問題,在平臺這裏都不叫問題。
上面的問題可以使用原子鎖Interlocked, https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked?view=net-5.0。

更多的關於線程安全的八股文 (請看這個,這個我面試騰訊考過,這個題目 O 了)

線程安全?# 變量#

線程安全的着力點,或者說問題的出發點是變量

BKyrLv

using System;
public class StaticTest
{
    static int count;
    int number;
    public StaticTest()
    {
        count = count + 1;
        number = count;
    }
    public void display()
    {
       Console.WriteLine("object={0}:count={1}", number, count); 
    }
}
class MainTest
{
    public static void Main()
    {
        StaticTest a = new StaticTest();
        a.display();
    }
}

• 不要認爲 [number是值類型,就存儲在棧區]• 引用類型的值指向堆區, 引用本身的值通常是 32 位或 64 位整形 • 局部變量的值存儲在棧區

1. 靜態成員:線程非安全

類的靜態成員即類變量,位於全局區 (靜態區),爲所有對象共享,一旦靜態變量被修改,其他對象對修改均可見,故線程非安全。

2. 實例成員:單例模式(只有一個對象實例存在)線程非安全,非單例線程安全

類的實例成員 (非靜態成員) 爲實例所有,在堆中分配,若在系統中只存在一個此類實例,在多線程環境下,“猶如” 靜態變量那樣,被某個線程修改後,其他線程對修改均可見,故線程非安全;

如果每個線程執行都是使用不同對象,那實例成員的修改將互不影響,故線程安全。

3. 局部變量:線程安全

每個線程執行時將會把局部變量放在各自棧幀的工作內存中,線程間不共享,故不存在線程安全問題。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/dz-W7oWpyxFyjVBH-8ihLg