实例讲解Java 自旋锁
作者:java小新人 发布时间:2021-09-17 09:38:50
标签:Java,自旋锁
一直以来不是怎么清楚自旋锁,最近有点时间,好好的学习了一下;
所谓的自旋锁在我的理解就是多个线程在尝试获取锁的时候,其中一个线程获取锁之后,其他的线程都处在一直尝试获取锁的状态,不会阻塞!!!那么什么叫做一直尝试获取锁呢?就是一个循环,比较经典的是AtomicInteger中的一个updateAndGet方法,下图所示(当然也可以直接看unsafe类中的getAndAddInt等类似方法);
我们可以看出在while循环中使用CAS去尝试更新一个变量,如果更新失败,就会一直在这个循环中一直在尝试;成功的话,就可以到最后的return语句;
由此我们可以大概知道如果自旋的线程过多,那么CPU的资源就会被大量消耗!!!
顺便提一个东西叫做原子引用,官方提供了AtomicInteger,AtomicBoolean等原子类,那么如果我们自己定义的类也需要有原子性怎么办呢?所以官方提供了一个AtomicReference类,可以将我们自己定义的类封装一下,就成了我们自己的原子类,例如AtomicReference<Student> atomicReference = new AtomicReference<>();
,然后我们对Student的实例进行CAS各种CAS操作;
栗子:
package TestMain;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
@Slf4j
public class TestMain80 {
//一个Thread类的原子引用
AtomicReference<Thread> atomicReference = new AtomicReference<>();
//加锁的方法
public void myLock() {
Thread currentThread = Thread.currentThread();
log.info("myLock--Thread:{}", currentThread.getName());
//这个就是自旋锁的核心,利用CAS比较当前原子引用中是否为null,如果是null,就把当前线程A放到里面去,
// 此时线程B再到这里,那么就会CAS失败,一直在while循环中
while (!atomicReference.compareAndSet(null, currentThread)) {
}
}
//解锁的方法
public void myUnlock() {
Thread currentThread = Thread.currentThread();
//CAS比较原子引用中是不是线程A,是的话就更新为null,此时在上面while中一直在自旋的线程B就可以跳出来了
atomicReference.compareAndSet(currentThread, null);
log.info("myUnlock--Thread:{}", currentThread.getName());
}
public static void main(String[] args) {
TestMain80 testMain80 = new TestMain80();
//线程A,首先加锁,然后等3秒中,然后释放锁
new Thread(() -> {
testMain80.myLock();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
testMain80.myUnlock();
}, "A").start();
//主线程等1秒,保证A线程先执行
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//线程B,加锁再释放锁
new Thread(() -> {
testMain80.myLock();
testMain80.myUnlock();
}, "B").start();
}
}
上面的就是一个自旋锁的栗子,执行结果中首先是执行A线程的myLock方法,获取锁成功,之后的B线程虽然也会执行mylock方法,但是会在while循环中一直阻塞,直到线程A调用了myUnlock方法释放锁,最后两行才会打印出来;
来源:https://www.cnblogs.com/wyq1995/p/12539853.html


猜你喜欢
- 这篇文章主要介绍了新手学习微服务SpringCloud项目架构搭建方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学
- 当构建一个图形化的Windows Form桌面应用程序并且需要执行在应用程序主UI线程之外的线程中长时间的任务时,BackgroundWor
- 根据poi接收controller层的excel文件导入 可使用后缀
- 本文实例为大家分享了Java身份证号码校验工具类的具体代码,供大家参考,具体内容如下import java.text.ParseExcept
- 前言一直对它们之间的关系感到好奇,SpringBoot既然是Spring的封装,那么SpringBoot在初始化时应该也会有Bean的加载,
- 1.前言在java当中,若是进行比较,大家可能第一时间想到,==或是!=,这种数学上的比较符>、接下来,我就分别介绍并演示
- 我正在开发一个软键盘,做得很好,但是我不知道如何自定义一个长按键的弹出窗口.我的键盘视图:<?xml version="1.
- 1. 什么是单例模式单例模式指的是在应用整个生命周期内只能存在一个实例。单例模式是一种被广泛使用的设计模式。他有很多好处,能够避免实例对象的
- 本篇文章主要介绍了java自动生成编号的实现,分享给大家,具体如下/** * 自动生成编号格式:yyMM+四位流水号 */ @Reques
- 组件在容器(比如Jframe)中的位置和大小是由布局管理器来决定的。所有的容器都会使用一个布局管理器,通过它来自动进行组件的布局管理。种类j
- -vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M 这里有几个问
- Android SDK已经提供有进度条组件ProgressDialog组件,但用的时候我们会发现可能风格与我们应用的整体风格不太搭配,而且P
- 这个工具比较简单,用于配合另外一个工具进行文件传送,废话少说,上代码import java.net.URL;import java.net.
- 最近几年玩得最疯狂的应该是发红包了,尤其是过年的时候特别受欢迎,下面写了红包的随机算法,其实挺简单的,仅是提供一种思路,希望可以给大家一些启
- TCP实现TCP协议需要在双方之间建立连接,通过输入输出流来进行数据的交换,建立需要通过三次握手,断开需要四次挥手,保证了数据的完整性,但传
- 1、编写一个Java程序在屏幕上输出“你好!”。 //programme name Helloworld.java public class
- 客户端import java.io.BufferedReader;import java.io.InputStreamReader;impo
- PopupWindow是一个弹出式窗口,它可以展示任意View。他会浮在当前窗口的上方展示。下面看代码:public class MyAct
- 小总结抛出异常:创建异常对象,封装异常信息然后通过throw将异常对象传递给调用者。不对异常进行处理只对异常进行抛出是非常不负责任的表现可以
- 1.介绍我们知道,我们要使一个类型支持foreach循环,就需要这个类型满足下面条件之一:该类型实例如果实现了下列接口中的其中之一:Syst