标签:数据 moni 假设 veh 最新 int illegal AC mon
今天终于又重新拿起了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是个可变类,是线程不安全的:
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返回的还是旧的位置。当然,如果为了保持数据的一致性,那么这样做就是优点;但如果想要得到车辆的实时位置,就不得不得到车辆位置的最新快照,
上述的方法会造成严重的性能问题。那么如何改进呢?在这里我给个提示:复制数据的原因是因为属性是线程不安全的,不能直接发布,那么,如果发布一个线程安全的属性,是否就解决了实时性的问题?
Java Concurrency in Practice 4.1-4.2相关问题及理解
标签:数据 moni 假设 veh 最新 int illegal AC mon
原文地址:https://www.cnblogs.com/cedriccheng/p/9016810.html