Java并发 - 线程安全类探索 设计车辆追踪器,获取车辆位置和更新车辆位置信息(坐标x,y)展示显示化大屏
版本一
非线程安全车辆对象【不可变】(MutablePoint)
线程安全车辆容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class MutablePoint { public int x, y; public MutablePoint () { this .x = 0 ; this .y = 0 ; } public MutablePoint (MutablePoint point) { this .x = point.x; this .y = point.y; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import java.util.Collections;import java.util.HashMap;import java.util.Map;public class MonitorVehicleTracker { 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 getLocations (String id) { MutablePoint mutablePoint = locations.get(id); return mutablePoint == null ? null : new MutablePoint (mutablePoint); } public synchronized void setLocations (String id, int x, int y) { MutablePoint mutablePoint = locations.get(id); if (null == mutablePoint) { throw new IllegalArgumentException ("No such ID :" + id); } mutablePoint.x = x; mutablePoint.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); } }
版本优缺点
优点
缺点
使用deepCopy方式保证线程安全,对象的大量创建会导致内存不足
getLocations时获取的车辆信息不是最新车辆信息
getLocations分析:
在getLocations和setLocations使用sync同步字段,在导出数据时,若locations对象数据很大,此时其他线程调用了setLocations时便会阻塞住,则当前线程导出的数据与用户查看的数据一致(数据一致性)。但数据没有发生更新。
版本二
线程安全车辆对象【不可变】(Point)
线程安全车辆容器(DelegatingVehicleTracker)
1 2 3 4 5 6 7 8 9 public class Point { public final int x,y; public Point (int x, int y) { this .x = x; this .y = y; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class DelegatingVehicleTracker { private final ConcurrentMap<String, Point> locations; private final Map<String, Point> unmodiflableMap; public DelegatingVehicleTracker (Map<String, Point> points) { locations = new ConcurrentHashMap <>(points); unmodiflableMap = Collections.unmodifiableMap(locations); } public Map<String,Point> getLocationsNotChange () { return Collections.unmodifiableMap(new HashMap <>(locations)); } public Map<String, Point> getLocations () { return locations; } public Point getLocations (String id) { return locations.get(id); } public void setLocations (String id, int x, int y) { if (locations.replace(id, new Point (x, y)) == null ) { throw new IllegalArgumentException ("invalid vehicle name:" + id); } } }
仔细观察上述版本一和版本二中getLocations及保存车辆的容器,容器如何保证线程安全,及getLocations如何保证数据一致性与保证获取的是最新数据。
版本三
线程安全车辆对象【可变】(Point)
线程安全车辆容器(DelegatingVehicleTracker)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class SafePoint { private int x, y; public SafePoint (int [] a) { this (a[0 ], a[1 ]); } public SafePoint (SafePoint p) { this .x = p.x; this .y = p.y; } public synchronized int [] get() { return new int []{x, y}; } public SafePoint (int x, int y) { this .x = x; this .y = y; } public synchronized void set (int x, int y) { this .x = x; this .y = y; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class PublishingVehicleTracker { private final Map<String, SafePoint> locations; private final Map<String, SafePoint> umodifiableMap; public PublishingVehicleTracker (Map<String, SafePoint> locations) { this .locations = new ConcurrentHashMap <>(locations); this .umodifiableMap = Collections.unmodifiableMap(this .locations); } public Map<String, SafePoint> getLocations () { return this .umodifiableMap; } public SafePoint getLocations (String id) { return locations.get(id); } public void setLocations (String id, int x, int y) { if (!locations.containsKey(id)) { throw new IllegalArgumentException ("invalid vehicle name :" + id); } locations.get(id).set(x, y); } }
观察上述版本二和版本三中如何保证车辆信息对象在可变条件下线程安全。
对现在有的线程安全类添加功能。
代码复用
开发成本及维护成本(原有的代码已经测试过)
假设需要一个线程安全链表,他提供一个原子的“若没有则添加(Put-If-Absent)” 同步的List已实现了大部分功能,我们可以根据他提供的contains和add方法来构造一个“若没有则添加”的操作。
实现”若没有则添加“的概念很简单:先检查再执行。先检查这个元素是否存在,不存在则进行添加
修改原始类(通常无法做到)
扩展类(并非所有类的状态都向子类公开,大部分不适合)
1 2 3 4 5 6 7 8 public class BetterVector <E> extends Vector <E>{ public synchronized boolean putIfAbsent (E x) { boolean absent = !contains(x); if (absent) add(x); return absent; } }
客户端加锁(非线程安全)
1 2 3 4 5 6 7 8 9 10 public class ListHelper <E>{ public List<E> list = Collections.synchronized (new ArrayList <E>()); public synchronized boolean putIfAbsent (E x) { boolean absent = !list.contains(x); if (absent) add(x); return absent; } }
客户端加锁(线程安全)
1 2 3 4 5 6 7 8 9 10 11 public class ListHelper <E>{ public List<E> list = Collections.synchronized (new ArrayList <E>()); public boolean putIfAbsent (E x) { synchronized (list){ boolean absent = !list.contains(x); if (absent) add(x); return absent; } } }
组合(用户只能通过ImprovedList 访问)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class ImprovedList <T> implements List <T> { private final List<T> list; public ImprovedList (List<T> list) { this .list = list; } public synchronized boolean putIfAbsent (T x) { boolean absent = !list.contains(x); if (absent) add(x); return absent; } public synchronized void clear () { list.clear(); } }
Complementary
服务商辅配商品订单库存同步预警报表
Service provider auxiliary commodity order inventory synchronization early warning report
ServiceSuitOrderStockSyncReport
1 ServiceSuitOrderStockSync