4

今朝、マルチスレッドでのロックに関するランダムなテストを行っていたところ、奇妙なことに、2 つの別々のインスタンスでプライベートな「文字列」をロックすると、他のスレッドの実行が実際にブロックされることがわかりました。以下のコードを参照してください。

私を混乱させるのは、2 つのオブジェクトの「文字列」が実際には 2 つの別個のオブジェクトであることです。なぜ一方をロックすると他方がブロックされるのでしょうか。(文字列を List のような他の参照型オブジェクトに置き換えた場合、他のスレッドの実行がブロックされないことに注意してください。これは実際に期待したことです...)

class Program {
    static void Main(string[] args) {
        Thread th = new Thread(DoWork);
        th.Start();

        Thread th2 = new Thread(DoWork);
        th2.Start();
    }

    static void DoWork() {
        Test importer = new Test();
        importer.SyncTest();
    }



}

public class Test {
    public void SyncTest() {
        string find = "test";
        lock(find) {                
            Console.WriteLine("thread starting...");
            Thread.Sleep(4000);
        }
    }
}
4

3 に答える 3

6

文字列定数は「interned」です。これは、入力すると次のことを意味します。

var s1 = "foo";
var s2 = "foo";

どちらも文字列「foo」の同じインスタンスです。同様に、異なるスレッドから同じように定義されたローカル変数を使用してメソッドを 2 回呼び出した場合も、同じインスタンスです。これは、パフォーマンス上の理由から行われます。

これは特殊なケースですが、文字列をロックするべきではありません。(新しいロック オブジェクトを作成するという奇想天外な解決策がうまくいかない状況はまだ見たことがありません -- private object lockObject = new object();)

于 2012-06-22T01:50:16.640 に答える
2

.NET のリテラル文字列はインターンされているため、同じリテラル文字列を使用するたびに、実際にはまったく同じオブジェクトを使用しています。したがって、参照する両方のスレッドが"test"同じオブジェクトを参照 (およびロック) しています。

新しいタイプまたは他のタイプを作成するListと、新しいオブジェクトが作成されるため、各スレッドは独自のオブジェクトをロックします。

于 2012-06-22T01:50:55.347 に答える
2

Testすべてのクラスが同じ文字列インスタンスを使用するため、文字列を使用するとブロックされます。C# は、メモリを節約するためにすべての文字列リテラルをインターンします。したがって、文字列「test」のインスタンスは 1 回だけです。

共通言語ランタイムは、インターン プールと呼ばれるテーブルを維持することにより、文字列ストレージを節約します。このテーブルには、プログラムでプログラムによって宣言または作成された一意の各リテラル文字列への単一の参照が含まれています。したがって、特定の値を持つリテラル文字列のインスタンスは、システム内に 1 回だけ存在します。

したがって、 のすべてのインスタンスはTest同じオブジェクトを使用してロックしています。

于 2012-06-22T01:51:19.870 に答える