难度
初级
学习时间
30分钟
适合人群
零基础
开发语言
Java
开发环境
- JDK v11
- IntelliJIDEA v2018.3
友情提示
- 本教学属于系列教学,内容具有连贯性,本章使用到的内容之前教学中都有详细讲解。
- 本章内容针对零基础或基础较差的同学比较友好,可能对于有基础的同学来说很简单,希望大家可以根据自己的实际情况选择继续看完或等待看下一篇文章。谢谢大家的谅解!
1.温故知新
前面在《“全栈2019”53篇Java多线程学习资料及总结》一章中介绍了Java多线程基础知识总结及学习资料。
在《“全栈2019”Java原子操作第一章:内存可见性volatile关键字解析》一章中介绍了内存可见性volatile关键字。
在《“全栈2019”Java原子操作第二章:i++是原子操作吗?何为原子性》一章中介绍了什么是原子性。
在《“全栈2019”Java原子操作第三章:比较并交换CAS技术详解》一章中介绍了什么是比较并交换CAS技术。
现在介绍原子操作类AtomicBoolean。
2.什么是原子操作类?
顾名思义,原子操作类就是实现了原子操作的类。
原子操作的概念和必备知识在前三章已经详细介绍过了,这里就不在赘述。不清楚的小伙伴请前去查阅相关章节。
2.AtomicBoolean简介
对于学过前三章的小伙伴来说,原子操作类就显得简单很多,而且里面的原理已经掌握得差不多了,所以本章就简单来介绍一下原子操作类之一:AtomicBoolean。
AtomicBoolean是一个以原子方式操作boolean值的类。
先简单来看一下AtomicBoolean类长什么样:
AtomicBoolean类很简单,它有两个构造方法:
- AtomicBoolean()
- AtomicBoolean?(boolean initialValue)
这两个构造方法都比较常用。
第二个构造方法AtomicBoolean?(boolean initialValue)可以指定初始值。
下面我们就来用一用AtomicBoolean。
3.AtomicBoolean应用场景
例如,我们某些应用只需初始化一次,当初始化完成之后用一个标识将其记录下来,后面要想知道应用是否已初始化过,只需判断初始化标识即可。
如果大家有更多关于AtomicBoolean的应用场景请在评论区留言,谢谢。
下面,来看看未使用AtomicBoolean的情况。
创建一个boolean类型的变量用于记录应用是否初始化:
然后,我们创建一个新线程并启动它:
接着,这个新线程就读到initialized变量,并且当initialized为false时执行某动作:
run()方法书写完毕。
假设主线程将应用初始化了,这里就将initialized置为true:
最后,我们为了将程序模拟的更真实,延时100毫秒表示主线程用于初始化应用的时间:
例子书写完毕。
运行程序,执行结果:
从运行结果来看,符合预期。程序一直在运行并没有停下来。
为什么说符合预期呢?
因为我们的initialized被缓存了,普通变量是不具备内存可见性的,所以while循环读的initialized变量一直是缓存中的,而缓存中的值为false,也一直没有变过,程序也就一直在运行没有停下来。
这个问题我们在《“全栈2019”Java原子操作第一章:内存可见性volatile关键字解析》一章中详细介绍过了,这里就不再赘述。
怎么解决?
这时,我们的AtomicBoolean类就派上用场了,用AtomicBoolean类替代boolean即可。
4.返回get()/设置set?(boolean newValue)当前值方法
还是上一小节的例子。
在用AtomicBoolean类替代boolean之前先说两个方法,因为下面我们会用到这两个方法:
- get()
- set?(boolean newValue)
下面依次来看看这两个方法。
get()方法在AtomicBoolean类中的源码:
get()方法用于获取AtomicBoolean对象的当前值;
set?(boolean newValue)方法在AtomicBoolean类中的源码:
set?(boolean newValue)方法用于设置AtomicBoolean对象的当前值。参数newValue是我们可以指定的新值。
接下来,我们将用AtomicBoolean类替代boolean:
那么while循环条件表达式中获取initialized值的方式就要有所改变,即调用AtomicBoolean对象的get()方法:
最后,我们设置initialized新值的方式也要有所改变,即调用AtomicBoolean对象的set?(boolean newValue)方法:
例子改写完毕。
运行程序,执行结果:
从运行结果来看,符合预期。程序如期停止下来,我们while循环读到initialized的值为true,循环条件(!true)不成立。
AtomicBoolean类基本上就算是用完了。是不是超级简单。
下面我们来看看AtomicBoolean类中需要看看的方法与源码。
如果你只是想简单用用AtomicBoolean类,那么只看上面内容即可,下面的内容可自行选择阅读。
5.AtomicBoolean类中记录value的值的类型是int而不是boolean
我们来看一下AtomicBoolean类中记录value值的类型:
可以看到AtomicBoolean类中记录value值的类型是int类型,而不是boolean类型。
这是因为我们原子操作会涉及到一个底层调用,这里的底层指的是C语言,在C语言中是没有boolean类型的,用的是0或1来表示boolean类型,0表示false,1表示true,也就是说0表示假,非0表示真。与其说在调用底层的时候将Java中的value(true和false)转换为0或1还不如在一开始记录value的时候,就将value用int型来记录,这样就省去转换的步骤,而且避免了不必要的错误。
6.AtomicBoolean类中的value具有内存可见性
AtomicBoolean类中的value是用volatile关键字所修饰的,所以它具有内存可见性:
不清楚什么是内存可见性的小伙伴可以去《“全栈2019”Java原子操作第一章:内存可见性volatile关键字解析》一章中学习下。
7.set?(boolean newValue)方法源码
我们简单来看下AtomicBoolean类的set?(boolean newValue)方法:
通过上面的内容我们知道value是用0或1来表示false和true的。
所以,这里如果我们设置的是true,那么value=1;
如果我们设置的是false,那么value=0;
8.get()方法源码
我们再来看下AtomicBoolean类的get()方法:
通过上面的内容我们知道value是用0或1来表示false和true的。
如果我们之前给的是true,即value=1。
那么value != 0就是1 != 0,即true。
9.CAS算法体现
我们之前在《“全栈2019”Java原子操作第三章:比较并交换CAS技术详解》一章中学习过什么是CAS算法。
在AtomicBoolean类中也有体现:
这就是AtomicBoolean类的compareAndSet(boolean expectedValue, boolean newValue)方法。
下面我们来试试compareAndSet(boolean expectedValue, boolean newValue)方法。
还是上一小节的例子。
只不过将“initialized.set(true);”替换为以下代码:
这里我们的预测值是false,新值给的是true。
例子改写完毕。
运行程序,执行结果:
从运行结果来看,符合预期。
这里我们也可以将预期值改为true,再来看一下:
例子改写完毕。
运行程序,执行结果:
从运行结果来看,符合预期。不但值没有改成功,而且程序也没有停下来。
最后,希望大家可以把这个例子照着写一遍,然后再自己默写一遍,方便以后碰到类似的面试题可以轻松应对。
祝大家编码愉快!
GitHub
本章程序GitHub地址:https://github.com/gorhaf/Java2019/tree/master/Thread/atomic/AtomicBoolean
总结
- AtomicBoolean是一个以原子方式操作boolean值的类。
- get()方法用于获取AtomicBoolean对象的当前值。
- set?(boolean newValue)方法用于设置AtomicBoolean对象的当前值。参数newValue是我们可以指定的新值。
- AtomicBoolean类中记录value值的类型是int类型,而不是boolean类型。
- AtomicBoolean类中的value是用volatile关键字所修饰的,所以它具有内存可见性。
至此,Java中AtomicBoolean相关内容讲解先告一段落,更多内容请持续关注。
答疑
如果大家有问题或想了解更多前沿技术,请在下方留言或评论,我会为大家解答。
上一章
“全栈2019”Java原子操作第三章:比较并交换CAS技术详解
下一章
“全栈2019”Java原子操作第五章:AtomicInteger介绍与使用
学习小组
加入同步学习小组,共同交流与进步。
- 方式一:关注头条号Gorhaf,私信“Java学习小组”。
- 方式二:关注公众号Gorhaf,回复“Java学习小组”。
全栈工程师学习计划
关注我们,加入“全栈工程师学习计划”。
版权声明
原创不易,未经允许不得转载!