AtomicBoolean详解

AtomicBoolean提供了一种原子性地读写布尔类型变量的解决方
案,通常情况下,该类将被用于原子性地更新状态标识位,比如
flag

1.基本用法

1.1.AtomicBoolean的创建

// AtomicBoolean 无参构造
AtomicBoolean ab = new AtomicBoolean();
assert !ab.get();
// AtomicBoolean 无参构造,等价于 AtomicBoolean(false)
ab = new AtomicBoolean(false);
assert !ab.get();

1.2.AtomicBoolean值的更新

**compareAndSet(boolean expect, boolean update):**对比并且设置boolean最新的值,类似于AtomicIntegercompareAndSet 方法,期望值与AtomicBoolean的当前值一致时执行新值的设置动作,若设置成功则返回true,否则直接返回false。

// 无参构造AtomicBoolean,默认为false
AtomicBoolean ab = new AtomicBoolean();
// 更改失败
assert !ab.compareAndSet(true, false);
// ab.get()==false
assert !ab.get();
// 更改成功
assert ab.compareAndSet(false, true);
// 更改后的值为true
assert ab.get();

weakCompareAndSet(boolean expect, boolean update): 同上。

set(boolean newValue): 设置AtomicBoolean最新的value值,该新值的更新对其他线程立即可见。

// 无参构造AtomicBoolean,默认为false
AtomicBoolean ab = new AtomicBoolean();
assert !ab.get();
// 设置新值,AtomicBoolean的最新值为true
ab.set(true);
assert ab.get();

getAndSet(boolean newValue): 返回AtomicBoolean的前一个布尔值,并且设置新的值。

// 无参构造AtomicBoolean,默认值为false
AtomicBoolean ab = new AtomicBoolean();
assert !ab.get();
// 前值依然为false
assert !ab.getAndSet(true);
// 更新后的结果为true
assert ab.get();

lazySet(boolean newValue): 设置AtomicBoolean的布尔值,同AtomicInteger的lazySet方法
get(): 获取AtomicBoolean的当前布尔值

2.AtomicBoolean源码分析

AtomicBoolean的实现方式比较类似于AtomicInteger类,实际上AtomicBoolean内部的value本身就是一个volatile关键字修饰的int类 型的成员属性。

public class AtomicBoolean implements java.io.Serializable {private static final long serialVersionUID =
4654671469794556979L;// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
// valueOffset将用于存放value的内存地址偏移量
private static final long valueOffset;
static {try {// 获取value的内存地址偏移量valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;

3.代码示例

import java.util.concurrent.atomic.AtomicBoolean;public class TryLock {// 1.在TryLock内部,我们借助于AtomicBoolean 的布尔原子性操作方法// 因此需要先定义一个AtomicBoolean并且使其初值为falseprivate final AtomicBoolean ab = new AtomicBoolean(false);// 2.线程保险箱,用于存放与线程上下文关联的数据副本private final ThreadLocal<Boolean> threadLocal = ThreadLocal.withInitial(()->false);// 可立即返回的lock方法public boolean tryLock(){// 3.借助于AtomicBoolean的CAS操作对布尔值进行修改boolean result = ab.compareAndSet(false, true);if (result){// 4.当修改成功时,同步更新threadLocal的数据副本值threadLocal.set(true);}return result;}// 锁的释放public boolean release(){// 5.判断调用release方法的线程是否成功获得了该锁if (threadLocal.get()){// 6.标记锁被释放,并且原子性地修改布尔值为falsethreadLocal.set(false);return ab.compareAndSet(true, false);} else{// 直接返回return false;}}
}

1处,我们定义了一个AtomicBoolean类型的属性ab,其初始值为false,表明当前的锁未被任何线程获得,也就是说某线程可以成功获得对该锁的持有。
2处,我们定义了一个ThreadLocal<Boolean>,并且重写其初始化方法返回false,该ThreadLocal的使用在TryLock中非常关键,我们都知道显式锁为了确保锁能够被正确地释放,一般会借助于try..finally语句块以确保release方法能够被执行,因此
为了防止某些未能成功获取锁的线程在执行release方法的时候改变ab的值,我们需要借助于ThreadLocal<Boolean>中的数据副本进行标记和判断。
3处,我们使用AtomicBooleancompareAndSet 方法对ab当前的布尔值进行CAS操作,当预期值与ab当前值一致时操作才能成功,否则操作将直接失败,因此执行该方法的线程不会进入阻塞,这一点很关键。
如果某线程成功执行了对ab当前布尔值的修改,那么我们需要将其在(4处)ThreadLocal<Boolean>关联的数据副本标记为true,以标明当前线程成功获取了对TryLock的持有。release方法需要秉承一个原则,那就是只有成功获得该锁的线程才有资格对其进行释放,反映到我们的代码中就是执行对ab当前值布尔值的更新动作,见5处。
6处确认当前有资格进行锁的释放以后,就可以对ab当前布尔值进行更新操作了,并且标记当前线程已将锁释放。

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static java.lang.Thread.currentThread;
import static java.util.concurrent.ThreadLocalRandom.current;
public class TryLockExample
{private final static Object VAL_OBJ = new Object();public static void main(String[] args){// 定义TryLock锁final TryLock lock = new TryLock();final List<Object> validation = new ArrayList<>();// 启动10个线程,并且不断地进行锁的获取和释放动作for (int i = 0; i < 10; i++){new Thread(() ->{while (true){try{// 尝试获取该锁,该方法并不会导致当前线程进入阻塞if (lock.tryLock()){System.out.println(currentThread() + ": get the lock.");// 进行校验,以确保validation中只存在一个元素if (validation.size() > 1){throw newIllegalStateException("validation failed.");}validation.add(VAL_OBJ);TimeUnit.MILLISECONDS.sleep(current().nextInt(10));} else{// 未获得锁,简单做个休眠,以防止出现CPU过高电脑死机的情况发生TimeUnit.MILLISECONDS.sleep(current().nextInt(10));}} catch (InterruptedException e){e.printStackTrace();} finally{// 在finally语句块中进行锁的释放操作if (lock.release()){System.out.println(currentThread() + ": release the lock.");validation.remove(VAL_OBJ);}}}}).start();}}
}

运行结果

Thread[Thread-0,5,main]: get the lock.
Thread[Thread-0,5,main]: release the lock.
Thread[Thread-0,5,main]: get the lock.
Thread[Thread-0,5,main]: release the lock.
Thread[Thread-0,5,main]: get the lock.
Thread[Thread-0,5,main]: release the lock.
Thread[Thread-0,5,main]: get the lock.
Thread[Thread-0,5,main]: release the lock.
Thread[Thread-0,5,main]: get the lock.
Thread[Thread-0,5,main]: release the lock.
Thread[Thread-0,5,main]: get the lock.
Thread[Thread-0,5,main]: release the lock.
Thread[Thread-0,5,main]: get the lock.
Thread[Thread-0,5,main]: release the lock.
Thread[Thread-0,5,main]: get the lock.
Thread[Thread-0,5,main]: release the lock.
Thread[Thread-0,5,main]: get the lock.
Thread[Thread-0,5,main]: release the lock.
Thread[Thread-0,5,main]: get the lock.
Thread[Thread-0,5,main]: release the lock.
Thread[Thread-0,5,main]: get the lock.
Thread[Thread-0,5,main]: release the lock.
Thread[Thread-0,5,main]: get the lock.
Thread[Thread-0,5,main]: release the lock.
Thread[Thread-4,5,main]: get the lock.
Thread[Thread-4,5,main]: release the lock.
Thread[Thread-4,5,main]: get the lock.
Thread[Thread-4,5,main]: release the lock.
Thread[Thread-4,5,main]: get the lock.
Thread[Thread-4,5,main]: release the lock.
Thread[Thread-4,5,main]: get the lock.
Thread[Thread-4,5,main]: release the lock.
Thread[Thread-4,5,main]: get the lock.
Thread[Thread-4,5,main]: release the lock.
Thread[Thread-4,5,main]: get the lock.
Thread[Thread-4,5,main]: release the lock.
Thread[Thread-4,5,main]: get the lock.
Thread[Thread-4,5,main]: release the lock.
Thread[Thread-4,5,main]: get the lock.
Thread[Thread-4,5,main]: release the lock.
Thread[Thread-4,5,main]: get the lock.
。。。忽略

4.总结

AtomicBoolean的使用方法,通常情况下,我们可以使 用AtomicBoolean来进行某个flag的开关控制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/609446.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习笔记之——3D Gaussian Splatting及其在SLAM与自动驾驶上的应用调研

之前博客介绍了NeRF-SLAM&#xff0c;其中对于3D Gaussian Splatting没有太深入介绍。本博文对3D Gaussian Splatting相关的一些工作做调研。 学习笔记之——NeRF SLAM&#xff08;基于神经辐射场的SLAM&#xff09;-CSDN博客文章浏览阅读967次&#xff0c;点赞22次&#xff0…

matlab生成列是0-255渐变的图像

图像大小&#xff1a;640512 8位灰度图 %% 生成图像 %大小&#xff1a;640*512 %类型&#xff1a;灰度图 %灰度值&#xff1a;列按照0-255渐变&#xff0c;故命名为column shade。 clc,clear all,close all; %输入的图 imadouble(imread(lenna2.bmp));%原图 imargb2gray(ima)…

MYSQL InnoDB引擎

逻辑存储结构 架构 内存架构 磁盘结构 后台线程 事务原理 redolog undo log MVCC 基本概念 实现原理 隐藏字段 undo log readview

闲聊篇-求职的点点滴滴~~

引言 求职之旅是一段充满挑战与机遇的旅程。它不仅仅是寻找工作的过程&#xff0c;更是一个自我探索和成长的过程。在这篇文章中&#xff0c;我们将探讨求职的各个方面&#xff0c;从准备简历到面试&#xff0c;再到最终拿到心仪的offer。 1. 简历&#xff1a;你的敲门砖 精…

如何使用 Golang 比较版本号大小?

目录 详细步骤 完整性和边界情况 使用三方库 小结 在日常开发中&#xff0c;比较版本号大小的情况是经常遇到的。因为版本号通常是字符串形式的&#xff0c;所以在 Go 语言中&#xff0c;比较版本号大小通常需要将字符格式的版本号串解析为可比较的数值&#xff0c;然后进行…

6个提升Python编程能力的PyCharm插件

大家好&#xff0c;PyCharm作为一款强大的集成开发环境&#xff0c;本身已经提供了许多功能&#xff0c;但一些插件将进一步扩展和增强PyCharm的能力。通过使用这些插件&#xff0c;大家能够更快速地编写代码、提高代码质量、进行调试和优化&#xff0c;并将开发体验提升到一个…

JVM优化:如何进行JVM调优,JVM调优参数有哪些

Java虚拟机&#xff08;JVM&#xff09;是Java应用运行的核心环境。JVM的性能优化对于提高应用性能、减少资源消耗和提升系统稳定性至关重要。本文将深入探讨JVM的调优方法和相关参数&#xff0c;以帮助开发者和系统管理员有效地优化他们的Java应用。 本文&#xff0c;已收录于…

软件测试|MySQL DISTINCT关键字过滤重复数据

简介 在MySQL中&#xff0c;有时候我们需要从表中检索唯一的、不重复的数据。这时&#xff0c;我们可以使用DISTINCT关键字来过滤掉重复的数据行。在本文中&#xff0c;我们将深入探讨MySQL中DISTINCT的用法以及如何在查询中使用它来得到不重复的结果集。 基本语法 DISTINCT…

14.网络编程入门和网络应用开发

网络编程入门 计算机网络基础 计算机网络是独立自主的计算机互联而成的系统的总称&#xff0c;组建计算机网络最主要的目的是实现多台计算机之间的通信和资源共享。今天计算机网络中的设备和计算机网络的用户已经多得不可计数&#xff0c;而计算机网络也可以称得上是一个“复…

最具代表性的意大利葡萄酒之一:阿马罗内

阿马罗内是最具代表性的意大利葡萄酒之一&#xff0c;适合搭配各种食物&#xff0c;包括肉类菜肴&#xff0c;面食&#xff0c;意大利调味饭和奶酪等等。阿马罗内是一款浓郁、复杂的意大利葡萄酒&#xff0c;富含水果味。 阿马罗内的食物搭配很有挑战性&#xff0c;因为考虑这…

CMake入门教程【核心篇】导入外部库Opencv

😈「CSDN主页」:传送门 😈「Bilibil首页」:传送门 😈「动动你的小手」:点赞👍收藏⭐️评论📝 文章目录 环境准备示例:在Windows上配置OpenCV路径示例:在Linux上配置OpenCV路径环境准备 首先确保你的系统中安装了CMake。可以通过以下命令安装: Windows: 下载并…

记一次生产事故排查

背景&#xff1a;刚接手一个新工程&#xff0c;是一个给国内top级医院开发的老项目&#xff0c;因为历史原因&#xff0c;代码质量略低&#xff0c;测试难度略高。 上线很久的功能&#xff0c;最近一直频繁的爆发各种问题&#xff0c;经排查发现都是因为在业务过程中im聊天账号…

权威评测:K9、sc、希喂三款主食冻干大比拼,哪款更适合布偶猫?

关注布偶猫的饮食&#xff1a;作为肉食动物&#xff0c;它们肠胃脆弱需谨慎对待。主食冻干是理想之选&#xff0c;它既符合猫咪天然的饮食结构&#xff0c;又采用新鲜生肉为原料。搭配其他营养元素&#xff0c;既美味又营养&#xff0c;还能增强抵抗力。我们将为您测评市场上热…

数模学习day08-拟合算法

这里拟合算法可以和差值算法对比 引入 插值和拟合的区别 与插值问题不同&#xff0c;在拟合问题中不需要曲线一定经过给定的点。拟 合问题的目标是寻求一个函数&#xff08;曲线&#xff09;&#xff0c;使得该曲线在某种准则下与所 有的数据点最为接近&#xff0c;即曲线拟…

揭开JavaScript数据类型的神秘面纱

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》 ​ ​ ✨ 前言 JavaScript作为一门动态类型语言,其数据类型一直是开发者们关注的话题。本文将深入探讨Jav…

深度解析分布式算法:构建高效稳定的分布式系统

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

算法:动态规划之字符串模式匹配

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 一、问题描述 二、常规算法 三、动态规划算法 总结 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、问题描述 给定一个字符串 (s) 和一…

uni-app中轮播图实现大图预览

参考效果 当轮播图滑动切换的时候更新自定义下标&#xff0c;当图片被点击的时候大图预览。 参考代码 商品详情页轮播图交互 <script setup lang"ts"> // 轮播图变化时 const currentIndex ref(0) const onChange: UniHelper.SwiperOnChange (ev) > …

MPEG4Extractor

1、readMetaData 必须要找到 Moov box&#xff0c;找到 Mdat box或者 Moof box&#xff0c;并且创建了 ItemTable 大端 box 分为 box header 和 box content&#xff1a; box header由8个字节组成&#xff0c;前面四个字节表示这个box 的大小&#xff08;包含这个头的8字节&a…

PCL 格网法计算点云的占地面积

目录 一、算法原理二、代码实现三、结果展示四、测试数据本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT生成的文章。 一、算法原理 该方法主要用于粗略统计机载点云的占地面积。方法原理是将点云沿 X O Y XOY