Java面试里经常问到自旋锁与互斥锁的区别,下面重点详解自旋锁与互斥锁的几个区别@mikechen
什么自旋锁?
自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
这种采用循环加锁,等待锁释放的机制就称为自旋锁(spinlock)。
Java多线程与并发编程里有很多应用,比如AtomicInteger的CAS实现原理就是自旋锁的典型实现。
AtomicInteger 的自增方法,incrementAndGet() 方法,代码如下:
public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } }
CAS(Compare And Swap)即比较并交换,CAS 是乐观锁技术,当多个线程尝试使用 CAS 同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。
什么是互斥锁?
互斥锁: 保证线程安全的一种锁机制,在同一时刻,只允许一个执行流去访问临界资源。
在Java多线与并发编程里的synchronized就是互斥锁的典型应用,可以保证多线程对共享资源的访问安全问题。
代码示例如下:
//Synchronized这个关键字加上之后两个线程不能同时执行,只能一个线程执行之后下一个线程执行 public static void main(String[] args) { SynchronizedDemo thread=new SynchronizedDemo(); Runnable runnable=()->thread.methodA(); //java8新特性lamdba表达式的Runnable创建线程 Runnable runnable2=()->thread.methodB(); new Thread(runnable).start(); new Thread(runnable2).start(); } static class SynchronizedDemo { public synchronized void methodA(){ System.out.println("线程1运行"); try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程1运行完毕"); } public synchronized void methodB() { System.out.println("线程2运行"); try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程2运行完毕"); } }
注意: 互斥锁是多个线程一起去抢,抢到锁的线程先执行,没有抢到锁的线程需要等待,等互斥锁使用完释放后,其它等待的线程再去抢这个锁。
自旋锁和互斥锁的区别
自旋锁是一种非阻塞锁,如果某线程需要获取自旋锁,但该锁已经被其他线程占用时,该线程不会被挂起,而是在不断的消耗CPU的时间,不停的试图获取自旋锁;
互斥量是阻塞锁,当某线程无法获取互斥量时,该线程会被直接挂起,该线程不再消耗CPU时间,当其他线程释放互斥量后,操作系统会激活那个被挂起的线程,让其投入运行;
如果被锁住的代码的执行时间很短,那我们应该选择开销比较小的自旋锁,因为自旋锁加锁失败时,并不会主动产生线程切换。
同理如果被锁住的代码的执行时间很长,建议使用互斥锁。
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》