web-dev-qa-db-ja.com

静的メソッドはスレッドセーフですか

各ページの構築にかかった時間を計算するために、任意のWebページによって呼び出される静的タイマークラスがあります。

私の質問は、静的クラスはスレッドセーフですか?私の例では、同時ユーザーは開始時間と停止時間に問題を引き起こしますか?たとえば、開始値と停止値を上書きする別のスレッド。

public static class Timer
{
    private static DateTime _startTime;
    private static DateTime _stopTime;    

    /// <summary>
    /// Gets the amount of time taken in milliseconds
    /// </summary>
    /// <returns></returns>
    public static decimal Duration()
    {
        TimeSpan duration =  _stopTime - _startTime;
        return duration.Milliseconds;
    }

    public static void Start()
    {
        _startTime = DateTime.Now;
    }

    public static void Stop()
    {
        _stopTime = DateTime.Now;
    }
}

このクラスは非静的クラスである必要がありますか?

(このクラスは、asp.netマスターページから呼び出されます。)

56
Th3Fix3r

静的メソッドは本質的にスレッドセーフではありません。 CLRでは、インスタンスメソッドと同じように扱われます。違いは、一般にmakeスレッドセーフにすることです。 (スレッドセーフではない.NET BCL静的メソッドは考えられません。)インスタンスメソッドは、スレッドセーフではないことがよくあります。典型的なパターンは、オブジェクトを作成して1つのスレッドから繰り返し使用するためです。 doesは複数のスレッドから使​​用する必要があります。関連する調整には、オブジェクトが安全に使用されることの確認が含まれます。非常に多くの場合、オブジェクト自体よりも調整コードで行う方が適切です。 (通常、操作のシーケンス全体を効果的にアトミックにしたい-オブジェクト内で実行できないこと。)

Timerクラスは、スレッドセーフではありません。2つのスレッドは互いのデータを簡単に踏むことができ、スレッドが期間を計算するときに「古い」データを使用するのを止めるものはありません。

代わりに Stopwatch クラスを使用してください-それが目的です。確かに、複数のスレッドから1つのインスタンスを使用する場合は、安全性を確保するために通常の手順を実行する必要がありますが、一般的にははるかに良い位置にいます。確かにStopwatchも完璧とはほど遠い-詳細については この質問 と以下のコメントを参照-しかし、それは少なくともその型が設計されているものです。 (知っている人は、いつか修正されるかもしれません...)

65
Jon Skeet

良い議論があります here これは、あなたの例がスレッドセーフではない理由のメカニズムと理由にもっと焦点を合わせています。

要約すると、最初に、静的変数が共有されます。静的メソッドに対してローカルであっても、ローカル変数にすることができれば、独自のスタックフレームを取得できるため、スレッドセーフになります。また、静的変数(つまり、このスレッドで他の人が言及したロックやその他のマルチスレッドプログラミング手法)を保護する場合は、サンプルの静的クラスをスレッドセーフにすることもできます。

第二に、あなたの例は、あなたが変更したり、その状態が他のスレッドによって作用されるかもしれない外部変数インスタンスを受け取らないので、あなたの例はその点でもスレッドセーフです。

23
Bill

あなたのタイマークラスは間違いなくスレッドセーフではありません。通常のクラスを作成し、時間を測定する必要があるたびにインスタンス化する必要があります。

Timer timer = new Timer();

timer.Start();
//...
timer.Stop();

decimal duration = timer.Duration();

さらに良いことに、まさにそれを行う組み込みの.NETクラスがあります。

Stopwatch sw = Stopwatch.StartNew();

sw.Stop();

TimeSpan duration = sw.Elapsed;
20

はい、あなたは正しいです、このクラスの静的メンバー/アクセサーは、異なるユーザーによって上書きされます。

これが、インスタンスと非静的メンバーがある理由です。

5
Tom