【并发编程】线程安全策略

时间:2023-01-05 18:03:35

线程封闭

线程封闭

把对象封装到一个线程里,只有这个线程能看到这个对象。

实现线程封闭

Ad-hoc 线程封闭:程序控制实现,最糟糕,忽略
堆栈封闭:局部变量,无并发问题
ThreadLocal 线程封闭:特别好的封闭方法

ThreadLocal 实例保存登录用户信息

public class RequestHolder {
    private final static ThreadLocal<Long> requestHolder = new ThreadLocal<>();

    /**
     * 添加数据
     * 在filter里将登录用户信息存入ThreadLocal
     * 如果不使用ThreadLocal,我们会需要将request一直透传
     * @param id
     */
    public static void add(Long id){
        // ThreadLocal 内部维护一个map,key为当前线程名,value为当前set的变量
        requestHolder.set(id);
    }

    /**
     * 获取数据
     * @return
     */
    public static Long getId(){
        return requestHolder.get();
    }

    /**
     * 移除变量信息
     * 如果不移除,那么变量不会释放掉,会造成内存泄漏
     * 在接口处理完以后进行处理(interceptor)
     */
    public static void remove(){
        requestHolder.remove();
    }
}

线程不安全的类与写法

1.StringBuilder 线程不安全,StringBuffer线程安全
原因:StringBuffer几乎所有的方法都加了synchronized关键字。

2.SimpleDateFormat
SimpleDateFormat 在多线程共享使用的时候回抛出转换异常,应该才用堆栈封闭在每次调用方法的时候在方法里创建一个SimpleDateFormat。
另一种方式是使用joda-time的DateTimeFormatter(推荐使用)。

3.ArrayList,HashMap,HashSet等Collections

4.先检查再执行

// 非原子性
if(condition(a)){
  handle(a);
}

同步容器

现在使用的比较少,主要使用并发容器。
ArrayList->Vector,Stack
HashMap->HashTable

Collections.synchronizedXXX (list,set,map)

并发容器

J.U.C下的工具类:【并发编程】【JDK源码】JDK的(J.U.C)java.util.concurrent包结构

ArrayList->CopyOnWriteArrayList
HashSet/TreeSet->CopyOnWriteArraySet/ConcurrentSkipListSet
HashMap/TreeMap->ConcurrentHashMap/ConcurrentSkipListMap

安全共享对象策略

安全地共享对象包括以下几种策略:

线程限制:一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改。
共享只读:一个共享只读的对象,在没有额外同步的情况下,可以被多个线程并发访问,但是任何线程都不能修改它。
线程安全对象:一个线程安全的对象或者容器,在内部通过同步机制来保证线程安全,所以其他线程无需额外的同步就可以通过公共接口随意访问它。
被守护对象:被守护对象只能通过获取特定的锁来访问。

参考资料:
慕课网高并发实战(六)- 线程安全策略