这篇文章将为大家详细讲解有关Java中自旋锁的作用有哪些,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。
当多个线程想同时访问同一个资源时,就存在资源冲突,这时,大家最直接想到的就是加锁来互斥访问,加锁会有这么几个问题:
- <李>
等待资源的线程进入睡眠,发生用户态向内核态的切换,有一定的性能开销;
李> <李>占用资源的线程很快就用完并释放,这时等待的线程被唤醒,又要立即切换回用户态;
那么,如果有一种方式,使得等待的线程先短暂的等待一会儿,有可能有两种结果:
- <李>
等待的时间超过了这一会儿,那没办法,只好进入睡眠;
李> <李>等待的时间还未超过,占用资源的线程释放了,这时等待的线程就可以直接占用资源。
这就是锁的小优化:自旋锁!自旋锁并不是真正的锁,而是让等待的线程先原地“小转“一下,小转一下,通常小转一下的实现方式很简单:
int SPIN_LOCK_NUM =, 64; int 小姐:=,0; boolean wait =,真的; do {=,wait //,尝试获取资源锁 },while (wait ,,, (+ + i), & lt;, SPIN_LOCK_NUM);
我们通过循环一定的次数来自旋。颜色\{红}{但是我们也应该知道,不进入休眠而原地打转,是会一直消耗CPU资源的,因此,才有了自旋限制!}但是我们也应该知道,不进入休眠而原地打转,是会一直消耗CPU资源的,因此,才有了自旋限制!
看下面的JDK源码:
public final class Unsafe { ,public final  int getAndSetInt (Object var1, long var2,, int var4), { int 才能;var5; do {才能 ,,var5 =, this.getIntVolatile (var2 var1也); ,,},而(! this.compareAndSwapInt (var2, var1,还以为,var5, var4)); , return 才能;var5; ,} }
我们可以看到,CAS就是采用的自旋锁方式,持续的尝试读取最新的 volatile 修饰的变量的值,并尝试去用期望的值去比较,然后更新。
不过这里我们要注意,因为是无限循环,因此我们要保证占用资源的线程很快就能释放,而不是长时间占用(当然,因为这里的源码系统也设定了 int 型变量,因此,占用该变量的线程很快就会使用完而释放)。
三、自旋锁的死锁
啥?怎么会有死锁? 自旋锁虽然好用,若我们只是停留在上面的分析,那么还是很肤浅的;虽然自旋锁有很大的优势,但同样缺点也不少,除了上面说的,原地打转(忙等待)会一直消耗CPU资源,同时,还会有一个潜在的可能缺陷:死锁。
3.1、系统中断
在聊死锁之前,我们需要先了解一下系统中断事件(大学课本里有这一章节,ASM汇编中也涉及到系统中断向量表):
中断是指,CPU正常运行期间,由于有内/外部事件,或者由程序预先安排的事件,引起CPU暂停当前工作,转而去处理该事件,当处理完该事件后再返回继续运行被中断(暂停)的程序。通常,操作系统将中断分为两类:外部中断(硬件中断)和内部中断(异常中断,即软件引起的);
例如:由IO设备引起的中断为硬件中断,比如,键盘输入,硬盘/光驱读写等;异常中断很好理解,比如 NullPointerException 等。
3.2、中断处理程序
系统提供了一个API使得我们的程序能够向系统申请注册一个中断处理程序(例如:程序接收用户的输入事件)。
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
参数含义如下:
irq: 中断号,系统定义好,具体可查看中断向量表;
handler: 中断后发生的ISR(Interrupt Service Routines),直接翻译为:中断服务路由;实际类似,是响应中断服务的程序;
flags: 中断标志;
name: 中断相关的设备的ASCII,如:"keyboard",这些名字会在/proc/irq 和/proc/interrupts 中使用;
dev: 用于共享中断线,传递驱动程序的设备结构。非共享类型的中断,直接设置成为 NULL
中断标志(flags):
IRQF_DISABLED: 内核处理该ISR期间,禁止其它中断(一般很少使用);
Java中自旋锁的作用有哪些