Java中的自旋锁spinlock详解
作者:java架构师-太阳
这篇文章主要介绍了Java中的自旋锁spinlock详解,自旋锁就是循环尝试获取锁,不会放弃CPU时间片,减伤cup上下文切换,缺点是循环会消耗cpu,需要的朋友可以参考下
自旋锁
过程
获取锁 访问共享资源 释放锁
自旋锁
循环尝试获取锁,不会放弃CPU时间片,减伤cup上下文切换,缺点是循环会消耗cpu
非自旋锁
如果获取不到锁,让线程休眠,CPU就可以在这段时间去做很多其他的事情,直到之前持有这把锁的线程释放了锁,于是CPU再把之前的线程恢复回来,让这个线程再去尝试获取这把锁。若再次失败,就再次让线程休眠,若成功,一样可以成功获取到同步资源的锁
如果在获取自旋锁时,没有任何执行单元保持该锁,那么将立即获取锁。 如果在获取锁时已经有持有者,那么锁操作将自旋,直到自旋锁的保持者释放了锁。
缺点
自旋锁一直占用着CPU,他在未获得锁的情况下,一直运行(自旋),所以占用着CPU,如果不能在很短的时间内获得锁,这无疑会使CPU效率降低
互斥锁与自旋锁区别
互斥锁 在未获得锁时,cup会进行切换,不会一直等待
自旋锁 在未获得锁时,一直占用着CPU,一直运行(自旋)抢占CUP
在多核机器中,如果锁住的“事务”很简单,占用很少时间,应该用自旋锁,自旋锁代价比互斥锁会小很多。
”事务”很快执行完毕,自旋的消耗远远小于陷入sleep和wake的消耗。如果锁住“事务”粒度较大,就应该使用互斥锁,因为如果用自旋锁,那么在“事务”执行过程中自旋很长时间还不如使得线程sleep
在单核机器中。自旋锁没有任何意义的,自旋锁只会浪费唯一核心的cpu 时间片,这个时刻没有任何线程会运行的。
所以单核机器中,不论锁住的”事务”的粒度大小都要使用。
手写自旋
public class SpinLockDemo { AtomicReference<Thread> atomicReference = new AtomicReference<>(); public void lock() { Thread thread = Thread.currentThread(); System.out.println(Thread.currentThread().getName()+"\t"+"----come in"); // 因为atomicReference没有set,所以是null,compareAndSet方法比较如果是null,就修改为当前线程,如果不是null,就循环判断 while (!atomicReference.compareAndSet(null, thread)) { } } public void unLock() { Thread thread = Thread.currentThread(); // 如果atomicReference存储的是当前线程,就修改为null atomicReference.compareAndSet(thread,null); System.out.println(Thread.currentThread().getName()+"\t"+"----task over,unLock..."); } public static void main(String[] args) { SpinLockDemo spinLockDemo = new SpinLockDemo(); new Thread(() -> { spinLockDemo.lock(); // 业务逻辑 try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } spinLockDemo.unLock(); },"A").start(); // 暂停500毫秒,线程A先于B启动 try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { spinLockDemo.lock(); spinLockDemo.unLock(); },"B").start(); } }
到此这篇关于Java中的自旋锁spinlock详解的文章就介绍到这了,更多相关自旋锁spinlock内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!