Java中的自旋锁与阻塞锁详解
作者:ゞ浪人与酒丶0
自旋锁
阻塞或者唤醒一个Java线程需要操作系统切换CPU 状态来完成,这种状态转换 需要耗费处理器时间 如果同步代码块到代码过于简单,状态转换到时间有kennel比用户执行代码到时间还长 在许多场景下,同步资源到锁定时间短,为了这小段时间切换线程,线程的挂起和恢复可能会让系统得不偿失,
这里是为了当前线程“ 稍等一下”, 我们需要让当前线程进行自旋 ,如果自旋完成后前面锁定同步资源的线程以及释放了锁,那么当前线程就没必要阻塞,而是直接获取同步资源,从而避免线程的开销 阻塞锁和自旋锁相反,阻塞锁如果没有拿到锁,就会直接阻塞,知道被唤醒
阻塞锁
阻塞锁是指当线程尝试获取锁失败时,线程进入阻塞状态,直到接收信号后被唤醒.(线程的状态包括新建、就绪、运行、阻塞及死亡)在JAVA中,能够唤醒阻塞线程的操作包括Object.notify, Object.notifyAll, Condition.signal, LockSupport.unpark(JUC中引入)
原理和源码分析
在 jdk 1.5 及以上并发框架 Java.util.concurrent 的 atomic 下 都是自旋锁实现的
AtomicInteger 的实现 :自旋锁实现原理是CAS AtomicInteger 中是调用底层unsafe 进行自增操作的源码中的 do-while 循环就是一个自旋操作,如果修改过程中一踏线程竞争导致修改失败,就在while 死循环,直至成功
package com.dimple.test; /** * 本实例演示下线程的自旋锁的实现 */ public class SpinLockDemo { private static AtomicReference<Thread> atomicReference=new AtomicReference<>(); public void lock(){ Thread thread=Thread.currentThread(); while(!atomicReference.compareAndSet(null,thread)){ System.out.println(thread.getName()+"自旋锁获取失败,重新获取中"); } } public void unlock(){ Thread thread=Thread.currentThread(); atomicReference.compareAndSet(thread,null); } public static void main(String[] args) { SpinLockDemo spinLockDemo=new SpinLockDemo(); new Thread(() -> { System.out.println(Thread.currentThread().getName()+"尝试获取自旋锁"); spinLockDemo.lock(); System.out.println(Thread.currentThread().getName()+"获取自旋锁成功"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } spinLockDemo.unlock(); System.out.println(Thread.currentThread().getName()+"释放自旋锁"); }).start(); new Thread(() -> { System.out.println(Thread.currentThread().getName()+"尝试获取自旋锁"); spinLockDemo.lock(); System.out.println(Thread.currentThread().getName()+"获取自旋锁成功"); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } spinLockDemo.unlock(); System.out.println(Thread.currentThread().getName()+"释放自旋锁"); }).start(); } }
Thread-0尝试获取自旋锁
Thread-0获取自旋锁成功
Thread-1尝试获取自旋锁
Thread-1自旋锁获取失败,重新获取中
Thread-1自旋锁获取失败,重新获取中
Thread-1自旋锁获取失败,重新获取中
Thread-1自旋锁获取失败,重新获取中
我们打开 AtomicInteger 源码看一下,这里是个 do while 循环
自旋锁的应用场景
自旋锁一般用于多核服务器,在并发度不是特别搞的情况下,比阻塞锁效率高
另外,自旋锁适用于临界区较小的情况,否则如果临界区很大,(线程一旦拿到锁,很多之后才会释放),那也是不适合的
到此这篇关于Java中的自旋锁与阻塞锁详解的文章就介绍到这了,更多相关自旋锁与阻塞锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!