• java并发编程实践学习(2)--对象的组合


    1. 先验条件(Precondition):某些方法包含基于状态的先验条件。例如,不能从空队列中移除一个元素,在删除元素前队列必须处于非空状态。基于状态的先验条件的操作成为依赖状态操作。
    2. 在单线程中,如果某操作无法满足先验条件,就只能失败,但在并发程序中先验条件可能会由于其他线程执行的操作而变成真。
    3. java中等待某个条件为真的各种内置机制(包括等待和通知机制)都与内置加锁紧密关联。
    4. 所有权和封装性总是相关联的:对象封装它拥有的所有权,对象对它的封装的状态拥有所有权。
    5. 发布了某个可变对象的引用,那就不再拥有独占的控制权。
    6. 容器类通常表现出一种“所有权分离”的形式。

    4.1设计线程安全的类

    在设计线程安全类的过程中,需要包含以下三个基本要素:

    • 找出构成对象状态的所有变量
    • 找出约束状态变量的不可变性条件
    • 建立对象状态的并发访问管理策略

     4.3委托给线程安全的类

    可以将共享资源委托给一个线程安全的类。比如ConcurrentHashMap,copyOnWriteArrayList.

    如果一个类时由多个独立且线程安全的状态变量组成,并且在所有的操作中都不包含无效状态转换,那么可以将线程安全性委托给底层状态变量。

    下面是一个监控车辆位置的实例。其中Point是线程安全不可变的类。

    /**
     * 不可变
     */
    @Immutable
    class Point{
        public final int x,y;
    
        Point(int x,int y ) {
            this.x = x;
            this.y = y;
        }
    }
    
    /**
     * 委托给线程安全类的车辆追踪器
     */
    @ThreadSafe
    class DelegatingVehicleTracker{
        private final ConcurrentHashMap<String,Point> locations;
        private final Map<String,Point> unmodifiableMap;
    
       public  DelegatingVehicleTracker(Map<String,Point> points) {
            this.locations = new ConcurrentHashMap<>(points);
            this.unmodifiableMap = Collections.unmodifiableMap(locations);
        }
    
        public Map<String,Point> getLocations(){
            return unmodifiableMap;
        }
    
        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);
            }
        }
    }
    

      如果一个状态变量是线程安全的,并且没有任何不变性条件来约束它的值,在变量的操作上也不存在任何不允许的状态转换,那么就可以安全地发布这个变量。

    同样是车辆追踪,我想要获取位置,还可以修改位置,安全性问题可以交给底层SafePoint:

    /**
     * 线程安全且可变的Point类
     */
    @ThreadSafe
    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;
        }
    }
    
    /**
     * 安全发布底层状态的车辆追踪器
     */
    @ThreadSafe
    class PublishingVehicleTracker{
        private final Map<String,SafePoint> locations;
        private final Map<String,SafePoint> unmodifiableMap;
    
        PublishingVehicleTracker(Map<String, SafePoint> locations, Map<String, SafePoint> unmodifiableMap) {
            this.locations = locations;
            this.unmodifiableMap = unmodifiableMap;
        }
    
        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);
        }
    }
    

      4.5将同步策略文档化

    在文档中说明客户代码需要了解的线程安全性保证,以及代码维护人员需要了解的同步策略。

    synchronized,volatile或者任何一个线程安全类都对应于某种同步策略,用于在并发访问时确保数据的完整性。一定要在忘记之前记录下来。

    可以使用@GuardedBy("this")或者别的来注释锁。

  • 相关阅读:
    php 3des加密解密
    mysql 用命令导入导出
    ubuntu16.04对硬盘进行分区格式化并设置开机自动挂载
    nginx
    iostat (转https://www.cnblogs.com/ftl1012/p/iostat.html)
    zabbix
    zabbix
    mac 录屏
    利用elasticsearch-dump实现es索引数据迁移附脚本
    rdbtool
  • 原文地址:https://www.cnblogs.com/woshimrf/p/5242029.html
Copyright © 2020-2023  润新知