线程安全的体现
不可变:对象被构建完后,其外部可见状态永远不会改变绝对线程安全:不管运行环境如何,调用者都不需要任何额外的同步措施相对线程安全:Java语言中的大部分线程安全类,或通常意义所说的线程安全。其保证单独的操作是安全的,对于一些特定顺序的连续调用,则需要额外的同步措施线程兼容:Java语言中的大部分类(ArrayList,HashMap等),对象本身并不是线程安全的,但是可以通过在客户端使用同步措施来保证对象在并发环境下安全使用,线程对立:无论使用哪种同步措施都不能保证线程安全,例如Thread的suspend resume等
线程安全的实现方法:
互斥同步:是一种悲观的并发策略,多个线程并发访问共享数据时,保证共享数据在同一时刻只能被一个(或者是一些,使用信号量时)线程使用;临界区,互斥量,信号量都是主要的互斥方式:synchronized,ReentrantLock等非阻塞同步:CAS指令,例如原子类的AtomicInteger.incrementAndGet()无同步方案: 可重入代码:不涉及数据共享的代码 线程本地共享:ThreadLocal
锁优化:
适应性自旋:互斥同步对性能最大的影响是阻塞的实现,挂起线程和恢复线程的操作都需要转入内核态中完成,带来性能并发压力。如果物理机上有一个以上的处理器,能让两个以上的线程同时并行执行,当一个线程请求一个已经被另一个线程所占用的锁时,我们就可以让这个线程不要阻塞,而是选择“稍等一下”,让这个线程执行自旋,不放弃处理器的时间,看看另一个线程是否很快释放锁锁消除:对于一些代码,虽然要求同步,但是被检测到不可能存在数据共享,则可以对竞争的锁进行优化消除,例如局部变量的StringBuffer对象的多次append操作。锁粗化:如果一系列的重复操作都对同一个对象频繁的加锁解锁,则可以将加锁同步的范围扩展(粗化)到整个操作序列的外部,例如上面的append(),就是扩展到第一个append()操作之前和最后一个之后,这样只需加锁一次轻量级锁:没有多线程竞争的前提下,减少传统的重量级锁在使用时对操作系统互斥量产生的性能消耗;其提升性能的依据是,对于绝大部分锁,在整个同步周期内都是不存在竞争的。偏向锁:(JDK1.6)消除数据在无竞争情况下的同步原语,如果轻量锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量,那偏向锁就是在无竞争的情况下把整个同步都消除掉,连CAS操作都不做
参考:深入理解Java虚拟机:JVM高级特性与最佳实践