深入理解JAVA虚拟机阅读笔记6——线程安全与锁优化

时间:2023-01-01 23:53:52

线程安全:如果一个对象可以安全的被多个线程同时使用,那它就是线程安全的

一、Java中的线程安全

1.不可变

  不可变的对象一定是线程安全的。String、枚举类型、java.lang.Number的部分子类如Long和Double等数值包装类型,BigInteger和BigDecimal等大数据类型。

  AtomicInteger和AtomicLong并非是不可变的。

2.绝对线程安全

  如Vector类是线程安全的,但是如果多个线程同时对Vector数据进行增加或者减少,那么Vector线程不是绝对线程安全的。

3.相对线程安全

  单独操作是线程安全的,连续操作需考虑同步问题。

4. 线程兼容

5. 线程独立

二、线程安全的实现方法

1. 互斥同步(阻塞同步)

基本概念:

  同步是指在多个线程并发访问共享数据时,保证共享数据在同一个时刻只被一个(或者一些)线程使用。

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

  互斥是因,同步是果;互斥是方法,同步是目的。

实现方法:

  synchronized对同一线程可重入,对不同线程阻塞。因为java线程是使用操作系统的原生线程实现的,因此synchronized是一个重量级操作。

  ReentrantLock重入锁。

  • 等待可中断
  • 可实现公平锁
  • 锁可以绑定多个条件

2. 非阻塞同步

  互斥同步是一种悲观锁,总是假定不去同步肯定会出问题。

  非阻塞同步是一种乐观锁,是基于冲突检测的方法,先进行操作,如果产生了冲突,重试。

  产生“ABA”问题。

3. 无同步问题

  可冲入代码

  线程本地存储

三、锁优化

1. 自旋锁和自适应自旋锁

  因为线程切换是一个重量级的操作,所以对于多处理器来说。如果线程被阻塞,那么会先执行一个忙循环(自旋操作)。

  自适应自旋转锁:自旋的次数会根据 自旋操作是否成功获取过锁来 自适应调节下次自旋次数。

2. 锁消除

  锁消除是指虚拟机即时编译器在运行时,对要求同步的代码,检测到不可能存在共享数据竞争的锁进行消除。

3. 锁粗化

  对一系列连续操作都是同一个对象反复加锁解锁的情况,将锁范围扩大到整个操作系列以外。

4. 轻量级锁

  在无竞争的情况下使用CAS操作去消除同步使用的互斥量。

5. 偏向锁

  在无竞争的情况下把整个同步都消除掉。