线程安全
AQS就是(AbstractQueuedSynchronizer)
线程安全定义
当多个线程访问某个类时,不管运行环境采用何种调度方式或者这些线程如何交替执行,并且在主调代码中不需要额外的同步或协同,这个类总能表现出正确的行为,那么这个类就称为线程安全的
Java语言中线程安全
在Java语言中将各种操作共享的数据分为五类: 不可变、绝对线程安全、相对线程安全、线程兼容和线程对立。
不可变
不可变的共享数据一定是线程安全的
绝对线程安全
绝对的线程安全就是当进行某个方法操作的时候是安全的,但是查找两个都是线程安全的就不一定线程安全,类似如:Vector中每个方法都安全,但是同时操作两个方法就不安全
相对线程安全
相对线程安全就是当对某个对象进行调用的时候安全,但是对其进行特定顺序调用的时候却不安全
线程兼容
对象本身不是线程安全的,但是可以通过一些同步方法来实现线程安全
线程对立
无论采取什么样的方法,都无法在多线程中运行的代码。例如:Thread类中的suspend()和resume()方法
线程安全实现方法
互斥同步
同步就是在多个线程并发访问共享数据时,保证共享数据在同一时刻只能被一个线程使用 例如: synchronized, ReentrantLock
非阻塞同步
基于检测的乐观主义策略:先进行操作,如果没有其他线程进行竞争操作,那么就执行成功,如果有其他线程进行操作,那就采取其他补偿措施(例如不断重试直到成功)
常见指令:
- 测试并设置 (Test and Set)
- 获取并增加 (Fetch-and-Increment)
- 交换 (Swap)
- 比较并交换 (Compare-and-Swap,CAS)
- 加载链接 (Load-Linked/Store-Conditional)
无同步方案
没有涉及到共享变量,所以无需同步
锁优化
自旋锁与自适应自旋
自旋锁(失败重试)可以使线程在没有取得锁的时候,不被挂起,而转去执行一个空循环,(即所谓的自旋,就是自己执行空循环),若在若干个空循环后,线程如果可以获得锁,则继续执行。若线程依然不能获得锁,才会被挂起
锁消除
锁消除是指虚拟机即时编译器在运行中,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除
锁粗化
一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作是出现在循环体中的,那即使没有线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗.。如果虚拟机探测到有这样一串零碎的操作都对同一个对象加锁,将会把加锁同步的范围扩展(膨胀)到整个操作序列的外部
轻量级锁
轻量级锁并不是用来代替重量级锁的,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。
偏向锁
偏向锁,简单的讲,就是在锁对象的对象头中有个ThreadId字段,这个字段如果是空的,第一次获取锁的时候,就将自身的ThreadId写入到锁的ThreadId字段内,将锁头内的是否偏向锁的状态设置为1