1.线程安全
①当多个线程访问一个对象时,如果不考虑这些线程在运行环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那么这个对象就是线程安全的
2.不可变
①在Java语言中,不可变的对象一定是线程安全的,无论是对象的方法实现还是方法的调用者,都不需要再采取任何的线程安全保障措施
②Java语言中,如果共享数据是一个基本数据类型,那么只要在定义时使用final关键字修饰它就可以保证它是不可变的
3.线程绝对安全
4.相对线程安全
5.互斥同步
①同步是指在多个线程并发访问共享数据时,保证共享数据在同一时刻只被一个线程使用。
②互斥时实现线程同步的一个手段,临界区、互斥量和信号量都是主要的互斥实现方式
③Java中,最基本的互斥同步手段就是synchronized关键字,关键字经过编译后,会在同步代码块的前后分别形成monitorenter和monitorexit这两个字节码指令,这两个字节码指令都需要一个reference类型的参数来指明锁定和解锁的对象
④在执行monitorenter指令时,首先要尝试获取对象的锁。如果这个对象没有被锁定,或者当前线程已经拥有这个对象的锁,把锁的计数器加一。在执行monitorexit时会将锁计数器减一,当计数器为0时,说就被释放了
⑤synchronized同步代码块对同一条线程来说是可重入的,不会出现把自己锁死的情况
6.等待可中断
①当前持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情,可中断特性对处理执行时间非常长的同步块很有帮助
7.公平锁:
①多个线程在等待同一个锁时,必须按照申请锁的时间顺序依次获得锁
8.绑定多个条件
9.非阻塞同步
①互斥同步最主要的问题是进行线程阻塞和唤醒所带来的性能问题,因此这种同步也称为阻塞同步
②基于冲突检测的乐观并发策略,通俗的说,就是先进行操作,如果没有其他线程征用共享数据,那么操作就成功了;如果共享数据有争用,产生了冲突,那就再采取其他的补偿措施
10.自旋锁与自适应自旋
①为了让线程等待,让线程执行一个忙循环(自旋),这项技术就是所谓的自旋锁
②自旋本身虽然避免了线程切换的开销,但他是要占用处理器时间的,因此,如果锁被占用的时间很短,自旋等待的效果就会非常好
11.锁消除
①
12.锁粗化
13.轻量级锁
①轻量级锁不是用来代替重量级锁的,他的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗
②HotSpot虚拟机对象头Mark Word
存储内容 | 标志位 | 状态 |
---|---|---|
对象哈希码、对象分代年龄 | 01 | 未锁定 |
指向锁记录的指针 | 00 | 轻量级锁定 |
指向重量级锁的指针 | 10 | 膨胀(重量级锁定) |
空,不需要记录信息 | 11 | GC标记 |
偏向线程ID、偏向时间戳、对象分代年龄 | 01 | 可偏向 |
③代码进入同步块的时候,如果此同步对象没有被锁定,虚拟机首先将在当前线程死亡栈帧中建立一个名为锁记录的空间,用于存储锁对象目前的Mark Word的拷贝。然后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向所记录的指针。如果这个更新成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位将转变为00,表示此对象处于轻量级锁定
14.偏向锁
①目的是消除数据在无争抢情况下的同步原语,进一步提高程序性能
②偏向锁就是在无竞争情况下把整个同步都消除掉
③锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不再需要再进行同步
④当锁对象第一次被线程获取的时候,虚拟机将会把对象头中的标志位设为“01”即偏向模式。同时CAS操作把获取到这个锁的线程的ID记录在对象的Mark Word之中,如果CAS操作成功,持有偏向锁的线程以后每次进入这个锁相关同步块时,虚拟机都可以不再进行任何同步操作
⑤当有另一个线程去尝试获取这个锁时,偏向模式就宣告结束