并发读源码——AtomicBoolean

1、AtomicBoolean介绍

上一节介绍了AtomicInteger加减操作的原子性,通过乐观锁实现,本节介绍AtomicBoolean,该类实现了对布尔类型比较和设置封装为原子操作。AtomicBoolean的源码以及用于都与AtomicInteger类似,可以参考上篇文章。例如如下操作

if(flag == true){
	flag = false;
}

该操作是线程不安全的,如果用AtomicBoolean类型封装布尔类型,就可以通过内部的compareAndSet方法实现布尔类型比较和设置的原子性,该方法也是通过乐观锁实现,后续进行分析。

2、源码解析

package java.util.concurrent.atomic;

import sun.misc.Unsafe;


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();
    private static final long valueOffset;

    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicBoolean.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    /*上一节中介绍了AtomicInteger,是调用底层的compareAndSwapInt进行比较设置值的,但是JVM没有compareAndSwapBoolean,
     * 所以AtomicBoolean就借鉴了AtomicInteger,通过把boolean类型转换成int类型,然后调用底层的compareAndSwapInt设置布尔类型的值
     * 当布尔类型值为true时,value的值转化为 1,false时,转化为0,可以参考下面的方法
     * */
    private volatile int value;

    /*AtomicBoolean有参初始化*/
    /*初始化布尔类型为true时,value的值转化为1,false时,value的值转化为0*/
    public AtomicBoolean(boolean initialValue) {
        value = initialValue ? 1 : 0;
    }

    /*无参初始化*/
    public AtomicBoolean() {
    }

    /*获取AtomicBoolean的变量value值*/
    public final boolean get() {
        return value != 0;
    }

    /*更新update值时,先比较expect与value的值是否相等,相等就把update的值更新到value中,否则更新失败*/
    /*运用该方法时,可以先从AtomicBoolean中读出value的值放到expect中,等更新update值时,如果expect中的值等于
     * AtomicBoolean中value值,说明在此期间没有其他线程操作value,线程是安全的,update更新成功;如果expect不等于
     * AtomicBoolean中value值,说明在此期间有其他线程操作了value,改变了value值,update失败
     * */
    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);
    }

    /*weakCompareAndSet与compareAndSet功能类似,都是比较expect值,然后更新update的值
     * 但是weakCompareAndSet不插入内存屏障,不能保证volatile或者final变量在内存中的执行顺序,只能保证最终一致性
     * 例如expect与AtomicBoolean中的value变量进行比较时,由于未出入内存屏障,value值没有从主内存中读取,导致比较的结果不准
     * */
    public boolean weakCompareAndSet(boolean expect, boolean update) {
        int e = expect ? 1 : 0;
        int u = update ? 1 : 0;
        return unsafe.compareAndSwapInt(this, valueOffset, e, u);
    }

    /*修改value值*/
    public final void set(boolean newValue) {
        value = newValue ? 1 : 0;
    }

    /*putOrderedInt不会立即把设置的newValue值同步到主内存中,但最终会进行同步,也就是只能最终一致性,一般很少用*/
    public final void lazySet(boolean newValue) {
        int v = newValue ? 1 : 0;
        unsafe.putOrderedInt(this, valueOffset, v);
    }

    /*先获取value值,然后把要更新的newValue值更新到value中,整个过程保证了原子性,是线程安全的*/
    /*采用乐观锁的方式更新布尔类型*/
    public final boolean getAndSet(boolean newValue) {
        boolean prev;
        do {
            prev = get();
        } while (!compareAndSet(prev, newValue));
        return prev;
    }

 
    public String toString() {
        return Boolean.toString(get());
    }

}

3、多线程用法

package com.lzj.atomic.integer.boolean1;

import java.util.concurrent.atomic.AtomicBoolean;

public class AtomicBooleanDemo {
	
	private AtomicBoolean atomicBoolean = new AtomicBoolean(false);
	
	public boolean read() {
		return atomicBoolean.get();
	}
	
	/*判断atomicBoolean中的value值是否是true,如果是,把value值更新我false,writeFlase执行结束;如果否,就执行do action操作,并循环执行while操作,直到value中的值为true*/
	public void writeFalse() {
		while(!atomicBoolean.compareAndSet(true, false)) {
			/*do action*/
			System.out.println(Thread.currentThread() + ": 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false");
		}
		System.out.println(Thread.currentThread() + ": 当前线程设置atomicBoolean的value值false成功,因为atomicBoolean当前的value值为true");
	}
	
	/*1秒后,把atomicBoolean中的value值设置为true*/
	public void set() throws InterruptedException {
		Thread.sleep(1);
		atomicBoolean.set(true);
	}
	
	public static void main(String[] args) {
		AtomicBooleanDemo atomicBooleanDemo = new AtomicBooleanDemo();
		Runnable run1 = () -> atomicBooleanDemo.writeFalse();
		Runnable run2 = () -> {
			try {
				atomicBooleanDemo.set();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		};
		
		Thread thread1 = new Thread(run1);
		Thread thread2 = new Thread(run2);
		thread1.start();
		thread2.start();
	}

}

执行结果如下:

Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false失败,因为atomicBoolean当前的value值为false
Thread[Thread-1,5,main]: 设置atomicBoolean的value值为true
Thread[Thread-0,5,main]: 当前线程设置atomicBoolean的value值false成功,因为atomicBoolean当前的value值为true

可见,开始Thread-0一直在循环执行while操作,当Thread-1线程把value值设置为true后,Thread-0结束while循环操作。

atomicBoolean.compareAndSet(true, false)是原子性,避免了线程不安全操作,该操作功能相当于如下操作

public void setFlag(boolean flag) {
	if(flag == true) {
		//do action
		flag = false;
	}
}

如代码所示,是先判断flag是否等于true,如果是,则把flag设置为false。该过程是线程不安全的,比如线程1判断flag == true,满足条件后,在执行flag = false操作之前,线程2把flag=false。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值