开始

线程安全的“安全程度”有强至弱来排序:
1)不变性,final
不可变对象:String、BigInteger 、BigDecimal 、Long、 Double
final带来的安全性是最简单和最纯粹的

2)绝对线程安全,(在java API中标注自己是线程安全的类,大多数都不是绝对的线程安全)

3)相对线程安全,保证这个对象单独的操作时线程安全的,在调用的时候不需要做额外的保障措施,但是对于一些特定顺序的连续调用,就可能需要在调用端使用额外的同步手段来保证调用的正确性。eg:Vector,HashTable;

4)线程兼容,对象本身并不是线程安全的,但可以通过调用端正确的使用同步手段来保证对象在并发环境中可以安全的使用;eg:Arraylist和HashMap;

5)线程对立
suspend()
resume()

线程安全的实现方法

1、互斥同步
同步是指在多个线程并发访问共享数据时,保证共享数据在同一个时刻只被一个(或者是一些,使用信号量的时候)线程使用。

互斥是实现同步的一种手段,临界区(Critical Section),互斥量(Mutex)和信号量(Semaphore)都是主要的互斥实现方式。

Java的线程是映射到操作系统的原生系统之上的,如果要阻塞或者唤醒一个线程,都需要操作系统来完成,这就需要从用户态转换到核心态中,因此状态转换需要耗费很多的处理器时间。所以synchronized是一个重量级的操作。

synchronized关键字编译后会在代码块前后形成monitorentermonitorexit两个字节码指令
ReentrantLock与synchronized很相似,但增加一些高级功能:

等待可中断,

公平锁,

锁可绑定多个条件。

公平锁指多个线程在等待同一个锁的时,必须按照申请锁的时间顺序来一次获得锁,非公平锁不保证这一点。

synchronized能够实现需求的时候推荐使用synchronized

2、非阻塞同步
互斥同步因为会阻塞线程,称为阻塞同步,开销很大。这是一种悲观的并发策略,认为不同步就会出问题。随着硬件发展,出现了非阻塞同步的方法,这是一种乐观的策略。它采用先行模式,就是先进行数据操作,如果没有竞争,那操作就成功了。如果发生冲突,再补救,通常是循环重试。这就避免了线程的挂起。

这种方案需要操作和冲突检测两个步骤具有原子性,实际是通过硬件提供的指令:

  • 检测并设置
  • 获取并增加
  • 交换
  • 比较并交换 CAS
  • 加载链接/条件存储 LL/SC

JDK1.5后, sun.misc.Unsafe类提供了对CAS的包装,这个类不是给用户用的,只有通过启动类加载器加载的类才能使用。只能通过反射或其他封装类库使用,例如Atomic。

这种方案存在ABA问题,尽管提供了AtomicAtampedReference通过版本解决,但如果非解决不能,还不如互斥同步的效率好。

3、无同步方案
可重入代码
线程本地存储
如ThreadLocal(ThreadLocalMap、ThreadLocalHashCode为键)

13.3 锁优化

JDK1.6对锁进行了大量优化措施,来提高并发效率。

  • 自旋锁:线程的挂起和恢复代价很大,自旋锁让竞争锁的线程自循环等待一会,看不能不能很快获得锁。省去了线程切换代价,但是自循环白白消耗cpu,所以它会自适应,收集数据判断等待是否值得,默认循环10次,如果预测值得就会加大次数,如果预测不值得,可能会直接挂起。
  • 锁消除:利用逃逸分析的结果,去掉不必要的锁
  • 锁粗化:如果小范围内频繁对一个对象加锁、释放锁,开销很大,会将锁范围扩大,用更少量的锁代替,减少开销。
  • 轻量级锁:传统锁使用互斥量实现,开销大。它的目的是 在没有多线程竞争的前提下,减少传统锁的开销。前面的对象内存布局中提到过,HotSpot对象头会存储运行时信息Mark Word,其中就包括锁信息。如果线程发现对象当前没有被锁定,将会在栈桢建立一个名为锁记录的空间,存储当前锁对象的Mark Word拷贝,然后用CAS尝试将对象头中的这部分改为指向该锁记录的指针。如果成功了,就获得了锁,并将Mark Word标记为轻量级锁定状态。如果失败了,看占有锁的是不是这个线程本身,是的话,可以继续执行,不是的话,说明产生竞争了,轻量级锁将会膨胀为重量级锁。释放锁同样CAS。可以看出,如果没有多线程竞争,大大提升性能,但是如果竞争出现,在传统锁基础上又绕远了一圈
  • 偏向锁:目的是消除无竞争下的锁原语,进一步提升性能。轻量级锁是用CAS代理互斥量,偏向锁是全去掉都不要了。锁偏向于获得它的线程,会在Mark Work中存储获得它的线程id,每次发现还是这个线程id就什么都不需要做,直接放行。如果产生竞争,可能重偏向或膨胀为轻量级锁