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。