1

静的マップがあります

private static Map<String, Car> cars = new HashMap<~>() //Map holding car objects

次のようなメソッド内で変数を使用します

private static String getCar(String name){
    return cars.get(name);
}

では、車にロックをかけたい場合は、スレッドセーフのために以下のようにしてもよろしいでしょうか。

private static void xyz() {
    synchronized(cars) {
        Car c = getCar("abc");
        c.setColor("Green");
    }
}

助言がありますか?

4

3 に答える 3

4

Java のsynchronizedキーワードを任意のオブジェクトに適用して、先に進む前にそのオブジェクトの「ロックを取得」(またはそのオブジェクトの「同期」) できます。他のプロセスが同時に同じオブジェクトで同期するコードを実行しようとすると、オブジェクトをロックしたプロセスが同期ブロックを終了するまでブロックされます。

synchronized同期するオブジェクトは、ブロックのどの部分でも実際に使用する必要はありません。同期ブロックでロックおよびロック解除することのみを目的とする単純なミューテックス オブジェクトである可能性があります。ただし、オブジェクトを単に同期しても、他のスレッドがそのオブジェクトでも同期しない場合、他のスレッドがそのオブジェクトを変更するのを防ぐことはできないことに注意することが重要です。これは、組み込みのロックではなく、プログラマー/慣例によって強制されたロックであり、共有オブジェクトを使用するすべてのコードは、同期するために「同意」する必要があります。

たとえば、上で記述したコードでは、xyz()メソッドが で同期するcars場合でも、次のような別のメソッドを記述できます。

public void changeCar() {
    Car myCar = cars.get("abc");
    myCar.setColor("Blue");
}

を呼び出さcars に変更しsynchronizedます。このメソッドは、 onxyz()を呼び出すコードを含まないため、メソッドが車を変更すると同時に「abc」車を変更する (つまり、スレッド セーフに違反する) 可能性があります。synchronizedcars

carsマップがスレッド セーフであること (つまり、2 つのメソッドによって同時に変更されないこと)を保証したい場合は、次のいずれかを行う必要があります。

  1. cars最初の呼び出しを変更するコードがsynchronized(cars)
  2. その上での put 操作と get 操作がスレッドセーフであることを保証するConcurrentHashMapを使用します。
于 2012-07-24T02:55:35.793 に答える
1

それは問題ありませんが、現在のコードでは、車のオブジェクトを完全にロックしていないことに注意してください。車のオブジェクトで再度同期しない限り、他のメソッドで車にアクセスして属性を設定できます。

public static void otherMethod() {
  synchronized(cars) {
     Car myCar = cars.get("abc");
     myCar.setColor("Red");
  }
}

ただし、メソッド xyz() が属性を設定する唯一の場所である場合、コードはスレッドセーフです。

于 2012-07-24T03:05:27.727 に答える
0

個々のメソッドの同期のみが心配な場合は、次を使用します

Map<String, Car> synchronizedMap = Collections.synchronizedMap(map);

これにより、マップ内のすべてのメソッドに同期が自動的に追加され、各メソッド呼び出しがアトミックになります。これは、おそらくスレッドに公開する必要があるマップです。

ただし、複数のメソッド呼び出し間で同期する必要がある場合 (何かが null の場合に get の後に put が続くなど)、上記のアプローチが必要になります。

Car オブジェクトもスレッドセーフである必要があることに注意してください。そのメソッドを見ないと、それがスレッドセーフであるかどうかはわかりません。

于 2012-07-24T03:48:54.230 に答える