博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
12、详解Java并发编程中的AtomicBoolean
阅读量:4035 次
发布时间:2019-05-24

本文共 3977 字,大约阅读时间需要 13 分钟。

如果看过我之前的文章都知道这几天一直在更新java多线程这块的知识点,因为这块的知识点确实是比较多而且也别繁杂,因此对于java多线程基础知识点也会在两个多月的时间全部写完,这篇文章主要是针对java并发包下的一个原子类AtomicBoolean的讲解。

一、为什么使用AtomicBoolean?

我们平时一般都是使用的boolean来表示布尔变量,但是在多线程情况下boolean是非线程安全的。为什么是非线程安全的呢?我们看下面的这个例子:

private volatile Boolean flag = false;publich void test() {
synchronized(flag) {
//去做其他的事:访问临界资源 flag = !flag; }}

大家可以看到,这个操作好像并没有什么问题,我们使用了synchronized关键字对flag对象进行上锁,这时候同一时刻就只能有一个线程去运行test方法中的代码了。如果你这样想那就大错特错了,其实此时synchronized对这块资源不起任何作用。为什么不起作用呢?我们来分析一下:

对于对象flag来说主要有两个值true和false。但是true和false却是两个不同的常量对象,也就是说synchronized关键字其实锁住的只是false对象,当下面test方法中把flag改为true就表示了另外一个对象。这就是为什么synchronized关键字失效的原因。

如何去解决这个问题呢?这时候我们的AtomicBoolean类就可以出马了,他可以很好的去解决这个问题。下面我们就来好好地分析一下AtomicBoolean类吧。

二、AtomicBoolean的使用

在一开始我们曾经也说到,在单线程中我们使用boolean是完全没有问题的,我们看如下代码:

public class Test6 implements Runnable{
public static boolean flag = true; private String name; public Test6(String name) {
this.name = name; } @Override public void run() {
if(flag) {
System.out.println(name + ",起床"); try {
Thread.sleep(1000); } catch (InterruptedException e) {
e.printStackTrace(); } System.out.println(name + ",上班"); try {
Thread.sleep(1000); } catch (InterruptedException e) {
e.printStackTrace(); } System.out.println(name + ",下班"); flag = !flag; }else {
System.out.println(name + "想进来却进不来"); } }}

上面的代码功能是这样的,起床上班下班这三件事,一个人做完另外一个才可以继续做。这种boolean情况,在单线程状态下是安全的,但是在多线程条件下就是非线程安全的。我们可以创建两个线程去测试一下:

在这里插入图片描述

原本我们想的是起床上班下班这三件事,一个人完成另外一个人再做,但是通过运行结果我们会发现,并列执行了。怎么才能实现我们的功能呢?我们再看下面的代码:

public class Test6 implements Runnable{
private static AtomicBoolean flag = new AtomicBoolean(false); private String name; public Test6(String name) {
this.name = name; } @Override public void run() {
if(flag.compareAndSet(false, true)) {
System.out.println(name + ",起床"); try {
Thread.sleep(1000); } catch (InterruptedException e) {
e.printStackTrace(); } System.out.println(name + ",上班"); try {
Thread.sleep(1000); } catch (InterruptedException e) {
e.printStackTrace(); } System.out.println(name + ",下班"); flag.set(false); }else {
System.out.println(name + "想进来却进不来"); } }}

此时我们换成AtomicBoolean,在运行一下看看:

在这里插入图片描述

我们会看到,此时执行的顺序就确定了张无忌想进来却进不来了。这就是其基本使用。下面我们分析一下其原理。

三、源码分析

想要了解其原理我们就必须要到源码中去看。在上面我们使用了compareAndSet方法,下面我们进入到这个方法中看看其源码实现:

/**     * Atomically sets the value to the given updated value     * if the current value {@code ==} the expected value.     *     * @param expect the expected value     * @param update the new value     * @return {@code true} if successful. False return indicates that     * the actual value was not equal to the expected value.     */    public final boolean compareAndSet(boolean expect, boolean update) {
int e = expect ? 1 : 0; int u = update ? 1 : 0; return unsafe.compareAndSwapInt(this, valueOffset, e, u); }

这个compareAndSet源码里面调用了unsafe的compareAndSwapInt方法,也就是使用了CAS机制,举一个我之前举的例子,这里expect和update是什么意思呢?也就是说我们现在的boolean如果不是except那就不更新,如果是我们预期的except,那就更新,更新的值就是update。也就是CAS原理,我们通过例子解释一下:

要给儿子订婚,你预期的儿媳妇是西施,但是儿子找的女朋友是貂蝉,你一看不是你预期的西施(except),一气之下就什么也不做,如果是预期的西施,那就给他们订婚。

注意:在这里我们还会发现一个问题,那就是我们的Boolean其实转化成了int类型,1表示true 0表示false。

这就是compareAndSet实现,底层使用的是CAS机制。当然还有很多其他的方法,我们可以看一下:

//返回当前值public final boolean get() {
return value != 0;}//先返回旧值,再设置新值public final boolean getAndSet(boolean newValue) {
boolean prev; do {
prev = get(); } while (!compareAndSet(prev, newValue)); return prev;}//设置新值public final void set(boolean newValue) {
value = newValue ? 1 : 0;}//设置新值,该操作会让Java插入Store内存屏障,避免发生写操作重排序public final void lazySet(boolean newValue) {
int v = newValue ? 1 : 0; unsafe.putOrderedInt(this, valueOffset, v);}

内存屏障,避免发生写操作重排序

public final void lazySet(boolean newValue) {
int v = newValue ? 1 : 0;
unsafe.putOrderedInt(this, valueOffset, v);
}
``

对于AtomicBoolean类其实是非常简单的。也是java并发机制中比较简单的类。这篇文章就先到这。如有问题还请指正。

在这里插入图片描述

转载地址:http://bibdi.baihongyu.com/

你可能感兴趣的文章
[leetcode BY python]1两数之和
查看>>
微信小程序开发全线记录
查看>>
Centos import torchvision 出现 No module named ‘_lzma‘
查看>>
PTA:一元多项式的加乘运算
查看>>
CCF 分蛋糕
查看>>
解决python2.7中UnicodeEncodeError
查看>>
小谈python 输出
查看>>
Django objects.all()、objects.get()与objects.filter()之间的区别介绍
查看>>
python:如何将excel文件转化成CSV格式
查看>>
Django 的Error: [Errno 10013]错误
查看>>
机器学习实战之决策树(一)
查看>>
机器学习实战之决策树二
查看>>
[LeetCode By Python]7 Reverse Integer
查看>>
[leetCode By Python] 14. Longest Common Prefix
查看>>
[leetCode By Python]111. Minimum Depth of Binary Tree
查看>>
[LeetCode By Python]118. Pascal's Triangle
查看>>
[LeetCode By Python]121. Best Time to Buy and Sell Stock
查看>>
[LeetCode By Python]122. Best Time to Buy and Sell Stock II
查看>>
[LeetCode By Python]125. Valid Palindrome
查看>>
[LeetCode By Python]136. Single Number
查看>>