线程安全在Wikipedia里面的定义:
Thread safety is a computer programming concept applicable to multi-threaded code. Thread-safe code only manipulates shared data structures in a manner that ensures that all threads behave properly and fulfill their design specifications without unintended interaction. There are various strategies for making thread-safe data structures.
线程安全的级别
- 线程安全 这种情况下其实没有线程安全问题,比如,每个人都有自己专用的卫生间,所以不会存在竞争
- 条件安全 所有人共用几个卫生间,抢到资源的就把门关上,通过门来隔离资源,后面的人就在外面等待
- 不安全 卫生间连门都没有,不能保证资源安全
实现线程安全的方式
- 避免共享数据结构,共享状态:(1)使用线程local变量 (2)使用不可变对象
- 共享不可避免,通过条件来确保:(1)互斥锁 (2)CAS原子操作
Java的线程安全策略
- java.lang.ThreadLocal<T>变量
- 不可变对象: String
- 互斥锁包括JDK5前的内置锁synchronized和JDK5后的java.util.concurrent.locks.Lock接口
- java.util.concurrent.atomic.*类
一般,避免共享数据结构能比较优雅的解决并发问题,这种程序对多线程更友好,性能更高。比如单机的ThreadLocal和分布式的Actor模型。这里面不存在竞争。其次是不可变变量,多线程操作的都是CopyOnWrite,这也是为什么一些动态编程语言如Scala的默认数据结构大多都是不可变的。不可变有其好处,但缺点也明显,如果需频繁对数据修改,那么会创建很多临时对象并占用较多内存。以上两种称无锁实现,性能好。如果避免不了共享数据,性能比较好的就是CAS原子操作,这种一般也称无锁,但其实是利用了OS的原子指令来实现,在竞争不激烈的场景下性能较好,一般的编程语言都有封装好的工具类。如果竞争激烈,其实性能未必比使用互斥锁高。互斥锁也称重量级锁,需OS干涉线程的调度,适用于竞争激烈的场景,这种方式下线程上下文的交换会降级系统的性能,使用时需注意。