Javaのマルチスレッド環境での静的メソッドの動作


114

私を悩ませ、私の心の中でいくつかの議論をする単純な愚かな質問があります。以下の質問に対する疑問をすべて捨てたいと思います。

class Clstest{

    public static String testStaticMethod(String inFileStr) {

        // section 0

        // section 1

        // do something with inFileStr

        // section 2

        // section 3

        return inFileStr;

    }

}

5つのスレッドがそれぞれClstest.testStaticMethod("arg-n")同時に呼び出しを実行していると仮定します。

スレッド1が呼び出しますClstest.testStaticMethod("arg-1")

スレッド1がセクション1にある場合、スレッド2はを呼び出しますClstest.testStaticMethod("arg-2")

次に、スレッド1はどうなりますか?スリープ状態になりますか?

スレッド1がチャンスを得たとき、一時停止したセクション1から実行を再開しますか?

1がありますとき、どのようにそれが起こるClstest.testStaticMethodと同じことがClstest.testStaticMethod、すべての5つのスレッド間で共有されていますか?

inFileStr複数のスレッドによって送信されたものを交換する可能性はありますか?


どの言語をターゲットにしていますか?
ΩmegaMan

3
@ OmegaMan:javaです
namalfernandolk 2013年

回答:


192

ハンス・パッサントの答えはいいです。しかし、これに出会い、Javaに慣れていない人のために、もう少し簡単なレベルで説明してみようと思いました。行くよ

Javaのメモリは、ヒープとスタックの2種類に分けられます。ヒープはすべてのオブジェクトが存在する場所であり、スタックはスレッドが作業を行う場所です。各スレッドには独自のスタックがあり、他の各スタックにアクセスできません。各スレッドには、現在実行しているコードのビットを指すコードへのポインターもあります。

スレッドは、新しいメソッドの実行を開始すると、そのメソッドの引数とローカル変数を独自のスタックに保存します。これらの値の一部は、ヒープ上のオブジェクトへのポインターである可能性があります。2つのスレッドが同じメソッドを同時に実行している場合、両方のスレッドがそのメソッドを指すコードポインターを持ち、スタックに引数とローカル変数の独自のコピーを持っています。スタック上のものがヒープ上の同じオブジェクトを指している場合にのみ、それらは互いに干渉します。その場合、あらゆる種類のことが発生する可能性があります。しかし、ハンスが指摘するように、文字列は不変(変更できない)なので、これが「共有」される唯一のオブジェクトである場合は安全です。

非常に多くのスレッドで同じメソッドを実行できます。JVMがJavaスレッドをOSスレッドにマップし、ハードウェアスレッドにスケジュールされているため、それらは同時に実行されていない可能性があります。したがって、複雑な同期メカニズムを使用しないと、これらのスレッドがインターリーブする方法をほとんど制御できません。

スリープはスレッドが自分自身に行うことであることに注意してください。


3
したがって、マルチコアプロセッサ環境では、複数のスレッドが同じコードを同時に実行している可能性がありますよね。また、シングルプロセッサ環境では、一度に実行されるスレッドは1つだけです。(それらの間で時間を共有する複数のスレッド。)それで、スレッドスケジューラが現在実行中のスレッド(A)からスレッド(B)にチャンスを与えるとき、スレッド(A)は一時停止したところからどのように再開しますか?どうやって再開ポイントを知るのですか?それは、「各スレッドは、現在実行しているコードのビットを指すコードへのポインターも持っている」ためなのでしょうか。あなたが言ったように?
namalfernandolk 2013年

6
あなたはそれを持っています。いくつかの点を明確にするために-最初に、スレッドのスケジュール方法はJavaの制御外です。ここでは、SunのHotspot JVMについて話しています。JVMはJavaスレッドをOSスレッドにマップし、OSは実行するスレッドを決定します。おっしゃるように、シングルコアマシンではOSは一度に1つしか実行できませんが、マルチコアマシンでは一度に複数を実行できます。第2に、スレッドは一時停止したことを実際には認識していません。スレッドが持つ唯一の情報は、プログラムポインター(コードへのポインター)とスタックであり、それらは以前とまったく同じように保存および復元されます。
selig 2013年

したがって、スレッドがローカルスコープ外の変数を使用していて、たとえば、あるスレッドが独自のスタックで変数(または変数へのポインター)をプルする前に、あるスレッドが変数の値を更新すると、スレッド間干渉が発生しますか?それは正しい理解ですか?
hariszhr 2016

2
もう少し正確に言うと...干渉が発生する可能性がありますが、発生する可能性はありますが、必ずしも発生するわけではありません...スレッドがヒープ上のものを共有する場合(非ローカル)。コードの異なる部分間の依存関係に依存する干渉が発生する可能性があるいくつかの異なる方法があります。一部の詳細が欠落しているため、あなたの例についてはわかりません。おそらく、スレッドAとBが両方とも共有の値を読み取り、その両方が読み取った値に基づいて更新するという潜在的な問題を参照している可能性があります。これはデータ競争です。
2016

1
@selig exのインスタンスメソッドのみを含むクラスがある場合:サービスクラスとそれがシングルトンである場合、サービスクラスは状態を保持する状態を保持しないため、複数のスレッドがインスタンスメソッドを同時に実行することを心配する必要はありません。クラスにインスタンス変数がある場合のみ存在します。私の理解は正しいですか?
Yug Singh

67

スリープ状態になりますか?

いいえ、スレッドを実行しても、意図的に互いに同期しない限り、他のスレッドには影響しません。複数のプロセッサコアがある場合、最近のすべてのマシンにありますが、これらのスレッドは正確に同時に実行される可能性があります。マシンに十分なコアがない可能性があるため、5つのスレッドを開始すると、その可能性は少し低くなります。オペレーティングシステムはそれらのいずれかを選択するように強制され、実行するたびにそれらを与えます。スレッドスケジューラのジョブ。その場合、スレッドは「スリープ」状態にはならず、単に一時停止され、スレッドスケジューラが実行する機会を与えるのを待ちます。スケジューラーによって中断されたところから再開します。

複数のスレッドによって送信されたinFileStrを交換する可能性はありますか?

そのような可能性はなく、スレッドには独自のスタックがあるため、メソッド引数とローカル変数はスレッドごとに一意になります。さらに文字列を使用すると、文字列は不変であるため、これらのスレッドが互いに干渉できないことが保証されます。

引数が別の種類の可変オブジェクトへの参照である場合、そのような保証はありません。または、メソッド自体が静的な変数またはヒープ上のオブジェクトへの参照を使用する場合。スレッドがオブジェクトを変更し、別のスレッドがそれを読み取る場合、同期が必要です。C#言語のlockキーワードは、このような必要な同期を実装するための定型的な方法です。メソッドが静的であるという事実は、そのような同期が必要になることは決してないということではありません。スレッドが同じオブジェクトにアクセスすることを心配する必要がないため、この可能性は低くなります(これを共有する)。


3
おっと、[java]タグを見たことがない。十分近い。
Hans Passant 2013年

投稿時に追加し忘れました。私の悪い。:)。とにかく答えてくれてありがとう。とても役に立ちました。
namalfernandolk 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.