• 设计线程安全的类 VS 发布线程安全的对象


    一、设计线程安全的类

    步骤:

    找出构成对象状态的所有变量

    找出约束状态变量的不变性条件

    建立对象状态的并发访问策略

    1.在现有的线程安全类中添加功能

    (1)重用能减低工作量和提高正确性

    (2)如果底层的类改变了同步策略,使用不同的锁来保护它的状态,则子类会被破坏

    class BetterVector<E> extends Vector<E>{
        public  synchronized boolean putIfAbsent(E e){
            boolean absent = !contains(e);
            if(absent){
                add(e);
            }
            return absent;
        }
    }

    2.客户端加锁机制

    (1)对于使用对象X的客户端,如果知道X使用的是什么锁,则使用X本身用于保护其状态的锁,来保护这段客户端代码

    (2)同样会破坏同步策略的封装

      A.错误示例:

    class ListHelper<E>{
        public List<E> list = Collections.synchronizedList(new ArrayList<E>());
        
        public synchronized boolean putIfAbsent(E e){
            boolean absent = !list.contains(e);
            if(absent){
                list.add(e);
            }
            return absent;
        }
    }

     B.正确示例:

    class ListHelper<E>{
        public List<E> list = Collections.synchronizedList(new ArrayList<E>());
        
        public  boolean putIfAbsent(E e){
            synchronized(list){
                boolean absent = !list.contains(e);
                if(absent){
                    list.add(e);
                }
                return absent;
            }
        }
    }

    3.组合:推荐方式

    class ImprovedList<E> implements List<E>{
    private final List<E> list;
    public ImprovedList(List<E> list){ this.list = list; } public synchronized boolean putIfAbsent(E e){ boolean absent = !list.contains(e); if(absent){ list.add(e); } return absent; } public synchronized boolean add(E e) { //委托..... } }

    二、发布线程安全的对象

    1. 发布对象:使对象能在当前作用域之外的代码中使用。既将对象的引用传递到其他类的变量和方法。

    (1)变量的静态初始化

    (2)声明为volatile变量 或 AtomicReferance对象

    (3)声明为final变量

    (4)将变量保存在线程安全的容器中(既保存在一个由锁保护的域中)

    2. 成员变量的初始化:

    (1)直接初始化

    (2)构造函数初始化

    3. 不可变对象、可变对象

    在Java内存模型中,final域能确保初始化过程的安全性,从而可以不受限制的访问不可变对象,并在共享这些对象时无需同步。

    在可变对象基础上构建的不可变类:虽然Set对象是可变的,但Set对象通过ThreeStooges的构造函数后,无法对其修改。

    public final class ThreeStooges {
        private final Set<String> stooges = new HashSet<String>();
        
        public ThreeStooges(){
            stooges.add("A");
            stooges.add("B");
            stooges.add("C");
        }
        
        public boolean isStooge(String name){
            return stooges.contains(name);
        }
    }
  • 相关阅读:
    数组相关常见的三种错误
    JMeter连接MYSQL数据库并进行操作详解
    JMeter实现动态关联——两个接口在不同的线程组
    Android : kernel中添加虚拟文件节点
    Android O : 系统原生锁屏密码位数限制及自动检查
    Android O : DNS列表获取及IPv4/IPv6优先级修改
    Android 打印调用栈的方法
    Android TV : 系统分区配置及增加私有分区
    Android TV : Mstar平台Audio Path及声音曲线配置
    Android TV : Mstar平台 GPIO 调试
  • 原文地址:https://www.cnblogs.com/yuyutianxia/p/3983562.html
Copyright © 2020-2023  润新知