chapter04_对象的组合_3_线程安全性的委托

  • (1) 从头开始构建一个类, 或将多个非线程安全的类组合为一个类时, Java监视器模式很有效(见"2_实例封闭.md");

    多个线程安全的类组合为一个类时, 可以考虑__委托方式__

    (2) 示例

    1° 基于监视器模式的车辆追踪

    MonitorVehicleTracker.java

      @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);
          }
      }
    

    MutablePoint.java

      @NotThreadSafe
      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;
          }
      }
    

    这个示例中, 虽然MutablePoint线程不安全, 但是MonitorVehicleTracker是安全的: 它采用了监视器模式, 用this作为锁, 并且内含的Map对象和Mutable对象都未曾发布

    2° 基于委托的车辆追踪

    DelegatingVehicleTracker.java

      @ThreadSafe
      public class DelegatingVehicleTracker {
    
          private final ConcurrentMap<String, Point> locations;
          private final Map<String, Point> unmodifiableMap;
    
          public DelegatingVehicleTracker(Map<String, Point> points) {
    
              locations = new ConcurrentHashMap<String, Point>(points);
              unmodifiableMap = Collections.unmodifiableMap(locations);
          }
    
          public Point getLocation(String id) {
    
              return locations.get(id);
          }
    
          public void setLocation(String id, int x, int y) {
    
              if (locations.replace(id, new Point(x, y)) == null) {
                  throw new IllegalArgumentException("invalid vehicle name: " + id);
              }
          }
    
          public Map<String, Point> getLocations() {
    
              return unmodifiableMap;
          }
    
          // Alternate version of getLocations 
          public Map<String, Point> getLocationsAsStatic() {
      
              return Collections.unmodifiableMap(new HashMap<String, Point>(locations));
          }
      }
    

    Point.java

      @Immutable
      public class Point {
    
          public final int x, y;
    
          public Point(int x, int y) {
              this.x = x;
              this.y = y;
          }
      }
    

    这种方式将线程安全委托给了ConcurrentMap类型的locations, 由于Point类是不可变的,所以如果想要实时更新点的位置, 可以调用getLocations()函数, 这样更新会立刻显示; 如果不需要发生变化的车辆位置, 可以调用getLocationsAsStatic()函数, 在这里采用了__浅拷贝__的方式(因为Point不可变, 复制Map的结构即可, 不需要复制它的内容)

    (3) 线程安全性可以委托给多个状态变量, 只要它们是彼此独立的

    示例

      public class VisualComponent {
    
          private final List<KeyListener> keyListeners = new CopyOnWriteArrayList<KeyListener>();
    
          private final List<MouseListener> mouseListeners = new CopyOnWriteArrayList<MouseListener>();
    
          public void addKeyListener(KeyListener listener) {
      
              keyListeners.add(listener);
          }
    
          public void addMouseListener(MouseListener listener) {
      
              mouseListeners.add(listener);
          }
    
          public void removeKeyListener(KeyListener listener) {
      
              keyListeners.remove(listener);
          }
    
          public void removeMouseListener(MouseListener listener) {
      
              mouseListeners.remove(listener);
          }
      }
    

    这个示例中, keyListeners和mouseListeners的类型是CopyOnWriteArrayList, 这是一个线程安全的容器类型, 并且由于它们互相独立, 所以VisualComponent的线程安全委托给了keyListeners和mouseListeners

    (4) 但是, 如果某个类含有复合操作, 那么委托方式就会失效, 此时必须依靠类自己的加锁机制(这个类似于如果只有一个状态变量时用volatile就行,但是有多个变量仅用volatile就会失效)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值