Java锁

公平锁
多个线程按照申请锁的顺序来获得锁;先检查等待队列是否为空,然后再CAS修改锁的状 态。
非公平锁
当一个线程申请锁时,如果锁处于空闲状态就直接获取锁,否则进入阻塞队列。直接CAS修改锁的状态,如果失败就进入等待队列。

读写锁
写锁被获取时,后续所有的读锁和写锁都会被阻塞。

自旋锁
线程获取锁时,会自旋一段时间等待锁的释放,而不是进入阻塞队列,一般有时间限制;
自适应自旋锁
线程的等待时间由上一次用于该锁的自旋时间和持有者状态决定。

可重入锁
能够支持一个线程对资源的重复加锁,例如一个线程在进行递归操作时可重复获取该锁,重复获取时其标志位加1;
非可重入锁
不支持一个线程对资源的重复加锁。

无锁
所有线程都能访问修改同一资源,但只有一个会修改成功,失败的会循环尝试,基于CAS原理。
偏向锁
如果一个锁一直被一个线程申请,这个线程就会自动获取该锁,而无需申请。会在对象头或栈帧中记录获取锁的进程的ID,再获取时,如果ID相同,就不用加锁和解锁;如果没有储存进程ID,就先看偏向锁的标志是否为1(判断该锁是否为偏向锁),为1就用CAS获取该锁,为0就使用CAS竞争该锁。
偏向锁只有在其他线程尝试竞争时,才会释放锁。当其他线程竞争时,它会等到全局安全点时暂停拥有锁的线程,如果线程还活着,就执行完之后给另一个线程或者将偏向锁升级为轻量级锁,不然就置为无锁状态。

优点:加锁和解锁不需要额外的消耗,适合一个线程访问一个代码块的场景
缺点:如果存在竞争,锁的撤销需要额外的消耗。

轻量级锁
将锁对象头的Mark Word复制到栈帧锁记录的空间中,然后使用CAS将Mark Word替换为指向锁记录的指针,如果失败就自旋等待。
锁撤销时使用CAS操作将锁记录复制回Mark Word中,如果失败,表示有其他线程竞争,锁就会膨胀为重量级锁。

优点:竞争的线程不会阻塞,提高了程序的响应速度,适用于代码块执行快,追求响应速度的场景;
缺点:线程会自旋消耗CPU;

重量级锁
将没有占有锁的线程全部放入阻塞队列。

CAS

Compare And Swap:乐观锁,先将值从内存空间中拷贝到工作空间中,当要修改时,先从内存中读取该值,如果与之前存的值相同,就修改,否则重新读取。

原理:通过调用Java原生包下的Unsafe类的CAS方法来实现,该方法被jvm编译为CAS汇编指令,是硬件层面的,其执行过程必是原子性的。

缺点:
1.底层使用的do while循环可能会时间过长;
2.只能保证单个共享变量的原子操作;
3.存在ABA问题(一个变量可能在过程中修改了多次,虽然前后结果一样)

ABA问题解决:调用AtomicStampReference类中的compareAndSet方法,该方法为变量设置了一个版本号,每次修改时版本号加一。

你可能感兴趣的:(Java锁)