web-dev-qa-db-ja.com

ローカル変数で同期するのは妥当ですか?

Javaメモリモデルから、すべてのスレッドが独自のスレッドスタックを持ち、ローカル変数が各スレッドの独自のスレッドスタックに配置されることがわかります。

そしてotherスレッドはこれらのローカル変数にアクセスできません。

それでは、どの場合、ローカル変数で同期する必要がありますか?

20
NingLee

あなたは以下のケースについて話している:

public class MyClass {
    public void myMethod() {
        //Assume Customer is a Class
        Customer customer = getMyCustomer();
        synchronized(customer) {
            //only one thread at a time can access customer object
              which ever holds the lock
        }
    }
}

上記のコードでは、customerはローカル参照変数ですが、同期ブロックを使用してオブジェクトへのアクセスを制限していますcustomerは、(一度に1つのスレッドによって)を指しています。

Javaメモリモデルでは、オブジェクトはヒープ内に存在し(参照はスタック内に存在するスレッドに対してローカルです)、同期はすべてにアクセスを制限します一度に1つのスレッドによるヒープ上のオブジェクト

要するに、ローカル変数(非プリミティブ)と言う場合、参照のみがローカルですが、実際のオブジェクト自体ではありません。つまり、実際にはヒープ上のオブジェクトを参照しています他の多くのスレッドからアクセスできます。このため、単一のスレッドが一度にそのオブジェクトにのみアクセスできるように、オブジェクトの同期が必要です。

23
developer

2つの状況があります。

  1. ローカル変数は、intまたはdoubleのようなプリミティブ型です。
  2. ローカル変数は、ArrayListのような参照型です。

最初の状況では、オブジェクト(参照タイプの変数によってポイントされる)でのみ同期できるため、できない同期します。

2番目の状況では、すべてローカル変数が何を指すかに依存します。他のスレッドも(できる)が指すオブジェクトを指している場合、コードが適切に同期されていることを確認する必要があります。

例:staticまたはインスタンスフィールドからローカル変数を割り当てた、または共有コレクションからオブジェクトを取得した。

ただし、オブジェクトがスレッドで作成され、そのローカル変数にのみ割り当てられ、スレッドから別のスレッドへの参照を決して与えず、オブジェクトの実装自体も参照を与えない場合、同期について心配する必要はありません。

12
Erwin Bolwidt

重要なのは、同期は目的のために行われるということです。 exactly 1つのスレッドが、保護に値する特別なアクティビティをいつでも実行できるようにするために使用します。

したがって、同期が必要な場合は、常に1つのスレッドよりもmoreになります。そしてもちろん、あなたはallそれらのスレッドがアクセスできるものをロックする必要があります。

または言い換えれば、あなたが建物に入らないようにするために、ドアをロックするあなたには意味がありません。

しかし、他の答えが指摘するように:それは実際には「ローカル」変数の定義に依存します。あなたが持っているとしましょう:

void foo() {
  final Object lock = new Object();
  Thread a = new Thread() { uses lock
  Thread b = new Thread() { uses lock

そして、その「ローカル」変数は、これら2つのスレッドのロックとして使用できます。さらに、その例は、特定のオブジェクトのmonitorで同期が行われるため機能します。そして、オブジェクトはヒープに常駐します。それらすべて。

5
GhostCat

はい、ローカル変数を使用して、ローカル変数と同じメソッドで定義および作成されたスレッドからのコードブロックへのアクセスを同期する場合は、意味があります。

2
Boris Pavlović