首页 > 《Java并发编程实践》中4.3.5章demo的一个疑问?

《Java并发编程实践》中4.3.5章demo的一个疑问?

Demo code结束后,有一句话没太理解:“PlublishingVehicleTracker是线程安全的,但是如果它在车辆位置的有效值上施加了任何约束,那么就不再是线程安全的”,SafePoint本身已经通过内置锁保证了对象内数据的线程安全,那么即使在set方法内加入了一些判断location位置的有效性代码也不会导致线程不安全吧。求指点!

代码如下:

@ThreadSafe
public class PublishingVehicleTracker {

    private final Map<String, SafePoint> locations;
    private final Map<String, SafePoint> unmodifiableMap;

    public PublishingVehicleTracker(
                            Map<String, SafePoint> locations) {
        this.locations
            = new ConcurrentHashMap<String, SafePoint>(locations);
        this.unmodifiableMap
            = Collections.unmodifiableMap(this.locations);
    }

    public Map<String, SafePoint> getLocations() {
        return unmodifiableMap;
    }

    public SafePoint getLocation(String id) {
        return locations.get(id);
    }

    public void setLocation(String id, int x, int y) {
        if (!locations.containsKey(id))
            throw new IllegalArgumentException(
                "invalid vehicle name: " + id);
        locations.get(id).set(x, y);
      }
}

@ThreadSafe
public class SafePoint {

    @GuardedBy("this") private int x, y;

    private SafePoint(int[] a) { this(a[0], a[1]); }

    public SafePoint(SafePoint p) { this(p.get()); }

    public SafePoint(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public synchronized int[] get() {
        return new int[] { x, y };
    }

    public synchronized void set(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

正好有这本书,重新看了下,对这最后两句我的理解是在强调虽然PublishingVehicleTracker和SafePoint本身都是threadsafe的,但是PublishingVehicleTracker发布出来的SafePoint是可变的,因此如果使用场景里需要基于PublishingVehicleTracker发布出来的Location(即SafePoint)做一些逻辑判断或者其他的操作时,结果可能是有问题的。

例如,如果A线程对通过getLocations获取的Map做遍历的同时,B线程通过setLocation方法修改其中的一个SafePoint值,那么A线程的处理结果就有了问题。

写了一个A线程内处理过程的样例代码,不一定确切,仅供参考:

    Map<String, SafePoint> locations = new HashMap<String, SafePoint>();
    locations.put("1", new SafePoint(1, 1));
    locations.put("2", new SafePoint(2, 2));

    PublishingVehicleTracker tracker = new PublishingVehicleTracker(locations);

    Map<String, SafePoint> m1 = tracker.getLocations();

    int greatThanTenCount = 0;
    for (String s1 : m1.keySet()) {
        SafePoint p1 = m1.get(s1);
        int [] v = p1.get();
        if (v[0] + v[1] > 10) {
            //可能的问题场景:此时B线程修改了某一个location的SafePoint值
            //在符合x+y和值大于10时,作业务处理
            greatThanTenCount ++; 
            System.out.println(s1 + "的(x+y)和值大于10了");
        }
    }
    if (greatThanTenCount > 2) {
        //可能的问题场景:此时B线程修改了某一个location的SafePoint值
        System.out.println("有超过2个的Location的x+y和值大于10,因此停车场不能再放车进来了");
    }
【热门文章】
【热门文章】