AtomicBoolean详解

背景

java中并发的类基本都在java.util.concurrent这个包中,包括前面介绍的大名鼎鼎的AQS。这个AtomicBoolean也是这个包的类,它支持在单个变量上解除锁的线程安全编程。java.util.concurrent.atomic此包中的类可以将volatile值,字段和数组元素的概念扩展到那些也提供院子条件更新操作的类。后续会一个一个研究。

CAS思想

先看下AtomicBoolean的用法:

1
boolean compareAndSet(expectedValue, updateValue);

我们看到了上面提到的一个在java并发中非常重要的一类算法:CAS:compare And set比较设置。我们用上面方法为例来解释下CAS的思想。当内存中可见的值如果和期望的值(expectedValue)一致,则将内存中的值修改为新值(updateValue),并且返回true。该操作是原子性的,意思是线程安全的。当多个线程同时访问某个对象时,如果其中一个线程通过CAS操作获得了访问权限,则其他线程只能在该线程处理完之后才能访问。这类似于同步关键字synchronized但是效率更高,因为没有锁的机制,即使在JDK7之后进行过优化。下面会举例子说明,在多线程中这种原子操作的必要性。例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
private static volatile AtomicBoolean aFlag = new AtomicBoolean(true);
private static Boolean bFlag = true;

public static void main(String[] args) {

ExecutorService es = Executors.newFixedThreadPool(10);

AtomicDemo demo = new AtomicDemo();
for(int i = 0 ;i < 10 ;i++) {
es.submit(new Runnable() {
@Override
public void run() {
//demo.executeAtomicLogic();
demo.executeLogic();
}
});
}

}

public void executeLogic() {

//synchronized (this) {
if (bFlag) {
try {
System.out.println(LocalDate.now() + " " + LocalTime.now() + "--" + Thread.currentThread().getName() + "--处理业务逻辑开始...");
Thread.sleep(5000);
System.out.println(LocalDate.now() + " " + LocalTime.now() + "--" + Thread.currentThread().getName() + "--处理业务逻辑完毕.");
} catch (Exception e) {
System.out.println(LocalDate.now() + " " + LocalTime.now() + "--" + Thread.currentThread().getName() + "--处理业务逻辑失败!!!");
} finally {
bFlag = !bFlag;
}
} else {

System.out.println(LocalDate.now() + " " + LocalTime.now() + "--" + Thread.currentThread().getName() + "--已经存在处理中的业务,请稍后再试!");
}
}

//}

上面代码是用一个boolea值来简单判断其它线程是否能进入业务代码执行,我们想看到的是线程1执行完后才能执行线程2,我们来看下结果:

可以看到这个结果是相当混乱,所有线程都抢占了资源。我们再看下使用了AtomicBoolean来看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class AtomicDemo {


private static volatile AtomicBoolean aFlag = new AtomicBoolean(true);
private static Boolean bFlag = true;

public static void main(String[] args) {

ExecutorService es = Executors.newFixedThreadPool(10);

AtomicDemo demo = new AtomicDemo();
for(int i = 0 ;i < 10 ;i++) {
es.submit(new Runnable() {
@Override
public void run() {
demo.executeAtomicLogic();
//demo.executeLogic();
}
});
}

}



public void executeAtomicLogic() {

if (aFlag.compareAndSet(true, false)) {

try{
System.out.println(LocalDate.now() + " " + LocalTime.now() + "--" + Thread.currentThread().getName() + "--处理业务逻辑开始...");
Thread.sleep(5000);
System.out.println(LocalDate.now() + " " + LocalTime.now() + "--" + Thread.currentThread().getName() + "--处理业务逻辑完毕.");
}catch(Exception e){
System.out.println(LocalDate.now() + " " + LocalTime.now() + "--" + Thread.currentThread().getName() + "--处理业务逻辑失败!!!");
}finally{
aFlag.set(true);
}
} else {

System.out.println(LocalDate.now() + " " + LocalTime.now() + "--" + Thread.currentThread().getName() + "--已经存在处理中的业务,请稍后再试!");
}
}
}

结果:

和加锁的效果完全一样。