Java Concurrency in Practice 4.1-4.2相關問題及理解

今天終於又從新拿起了Java Concurrency in Practice,以前被虐的體無完膚,在看這本書以前,有一部分本身寫的代碼我根本沒意識到是線程不安全的,還真的是要惡補這方面的知識。安全

1.Java監視器模式

監視器模式其實很簡單,就是用私有對象的鎖或者內置鎖來保證所屬對象的線程安全性。這裏引入一個例子:車輛追蹤性能

public class MonitorVehicleTracker {
    private final Map<String, MutablePoint> locations;
    
    public MonitorVehicleTracker(Map<String, MutablePoint> locations) {
        this.locations = 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 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<>();
        for(String id : m.keySet())
            result.put(id, new MutablePoint(m.get(id)));
        return Collections.unmodifiableMap(result);
}

這裏MutablePoint是個可變類,是線程不安全的:this

public class MutablePoint {
    public int x, y;
    
    public MutablePoint() { x = 0; y = 0; }
    public MutablePoint(MutablePoint p) {
        this.x = p.x;
        this.y = p.y;
    }
}

細心的讀者確定發現了,MonitorVehicleTracker類中幾乎每個方法都要複製MutablePoint或者locations的值,緣由在於,這倆不是線程安全的,不能直接發佈出去,因此只能發佈一個副本,可是這又出了新的問題:雖然MonitorVehicleTracker類是線程安全的,可是因爲數據都是複製的,那麼假設線程A調用了getLocations()方法獲得了位置,此時車的位置變化,線程B調用setLocation()修改了內部變量locations,這時車輛的位置已經修改了,可是線程A返回的仍是舊的位置。固然,若是爲了保持數據的一致性,那麼這樣作就是優勢;但若是想要獲得車輛的實時位置,就不得不獲得車輛位置的最新快照,上述的方法會形成嚴重的性能問題。那麼如何改進呢?在這裏我給個提示:複製數據的緣由是由於屬性是線程不安全的,不能直接發佈,那麼,若是發佈一個線程安全的屬性,是否就解決了實時性的問題?spa

相關文章
相關標籤/搜索