2017-03-20 10 views
1

"Java Concurrency in Practice"本にはスレッドセーフであるとされているMonitorVehicleTrackerコード例があります。工事中のスレッドセーフ

@ThreadSafe 
public class MonitorVehicleTracker { 
    @GuardedBy("this") private final Map<String, MutablePoint> locations; 

    public MonitorVehicleTracker(Map<String, MutablePoint> locations) { 
     this.locations = deepCopy(locations); 
    } 

    public synchronized Map<String, MutablePoint> getLocations() { 
     return deepCopy(locations); 
    } 

    public synchronized MutablePoint getLocation(String id) { 
     MutablePoint loc = locations.get(id); 
     return loc == null ? null : new MutablePoint(loc); 
    } 

    public synchronized void setLocation(String id, int x, int y) { 
     MutablePoint loc = locations.get(id); 
     if (loc == null) 
      throw new IllegalArgumentException("No such ID: " + id); 
     loc.x = x; 
     loc.y = y; 
    } 

    private static Map<String, MutablePoint> deepCopy(Map<String, MutablePoint> m) { 
     Map<String, MutablePoint> result = new HashMap<String, MutablePoint>(); 

     for (String id : m.keySet()) 
      result.put(id, new MutablePoint(m.get(id))); 

     return Collections.unmodifiableMap(result); 
    } 
} 

しかし、コンストラクタの引数はlocationsdeepCopy()通話中に別のスレッドによってに変更された場合を考えることができます。これにより、keySet()を反復しながらConcurrentModificationExceptionがスローされる可能性があります。

つまり、MonitorVehicleTrackerは完全にスレッドセーフではありませんか?またはスレッドセーフは、オブジェクトの構築が完了した後にのみ表示され、MonitorVehicleTrackerインスタンシエーション中にlocationsが変更されないようにするための呼び出しコードがありますか?

答えて

2

いいえ、クラスはまだスレッドセーフです。

オブジェクトが初期化に失敗した場合、そのクラスがスレッドセーフではなくなるわけではありません。これは、そのスレッドのthread-saftey契約を破る別のスレッドによって引数が誤って変更されたため、初期化に失敗したスレッドセーフなクラスです。

+0

右; 'locations'の' Map'実装はスレッドセーフではありませんが、 'MonitorVehicleTracker'はです。 – erickson

+0

同じことが、スレッドインターリーブのためにクラス不変条件が構築中に壊れている場合にも当てはまりますか? –

+0

@PavloViazovskyy私はそう言うだろう –

関連する問題