第13章 线程安全与锁优化

来源:互联网 发布:cf变枪软件 编辑:程序博客网 时间:2024/05/29 15:03
一、线程安全
1. 线程安全级别有5种:
不可变,绝对线程安全,相对线程安全,线程兼容,线程对立

(1)不可变
保证对象状态不可变是最简单最纯粹的安全

(2)绝对线程安全
在线程之间不需要使用任何额外的手段就可以实现线程安全,绝对线程安全很难达到,一般都是相对线程安全

(3)相对线程安全
在一个线程内部或一个对象内部是线程安全的,但是多线程之间需要额外的手段保证线程安全

(4)线程兼容
对象本身不是线程安全的,但是可以使用同步手段保证线程安全,平常所说一个类不是线程安全的,大多数指的是这种

(5)线程对立
不管调用端是否采取了同步措施,都无法在多线程环境中并发使用的代码

2. 线程安全(线程同步)的实现方法:
(1)阻塞同步:synchronized和ReentrantLock
(2)非阻塞同步:基于冲突检测的CAS操作
(3)无同步方案

(1)阻塞同步
阻塞同步的方法主要有两种:
synchronized和java.util.concurrent包中的ReentrantLock
缺点:
(1)进行线程阻塞和唤醒会带来性能问题,因为需要在用户态和核心态之间切换,消耗CPU时间
(2)是一种悲观锁,在可能发生问题的地方都加锁,而不管实际是否真的需要加锁

在性能上synchronized和ReentrantLock基本持平,只是在功能上ReentrantLock更全面
因此在满足需求的情况下,优先考虑使用synchronized实现同步

(2)非阻塞同步
基于冲突检测的非阻塞同步,是一种乐观的并发策略
需要操作和冲突检测具有原子性,语义上需要多次操作的行为只通过一条指令完成,使用CAS,由硬件实现

二、锁优化
1. 自旋锁与自适应自旋
(1)自旋锁
并不阻塞线程,而是让线程执行一个忙循环,依然占有CPU
确定一个自旋次数,如果自旋超过限定的次数仍然没有获得锁,就使用传统的方式挂起线程

(2)自适应自旋
不固定自旋次数,而是根据上次自旋时间以及锁的拥有者状态来决定
如果上次自旋获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也有可能成功,进而允许自旋等待更长的时间
如果对于某个锁,自旋很少成功获得过,那么在以后要获得这个锁时,可能会省略掉自旋,而是直接挂起线程

2. 锁消除
即时编译器在编译时将会对不需要进行同步的代码进行锁消除
判断能否进行锁消除的主要依据就是对象是否会发生逃逸(方法逃逸和线程逃逸)

3. 锁粗化
扩大锁的范围,使得对小范围的代码不会频繁地进行加锁
比如需要循环进行A操作,而A本身是加锁的,就可以把锁扩大到整个循环外面
又比如进行A,B,C操作,ABC都是加锁的,可以把锁扩大到ABC外面
0 0
原创粉丝点击