1. AtomicInteger不是final类型,如何保证线程安全?
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
/*
* This class intended to be implemented using VarHandles, but there
* are unresolved cyclic startup dependencies.
*/
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");
private volatile int value;
/**
* Creates a new AtomicInteger with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
/**
* Creates a new AtomicInteger with initial value {@code 0}.
*/
public AtomicInteger() {
}
public final int getAndIncrement() {
return U.getAndAddInt(this, VALUE, 1);
}
...
}
用volatile关键字修饰value字段
AtomicInteger用value字段来存储数据值,volatile关键字保证了value字段对各个线程的可见性。各线程读取value字段时,会先从主内存把数据同步到工作内存,这样保证可见性。
Unsafe实现操作原子性,用户在使用时无需额外的同步操作。
如AtomicInteger提供了自增方法getAndIncrement,其内部实现是由Unsafe类的compareAndSetInt方法来保证的。
// jdk.internal.misc.Unsafe
/**
* Atomically updates Java variable to {@code x} if it is currently
* holding {@code expected}.
*
* <p>This operation has memory semantics of a {@code volatile} read
* and write. Corresponds to C11 atomic_compare_exchange_strong.
*
* @return {@code true} if successful
*/
@HotSpotIntrinsicCandidate
public final native boolean compareAndSetInt(Object o, long offset,
int expected,
int x);
compareAndSetInt方法是一个CAS操作,用native关键字修饰。
原理:先比较内存中的值与expected是否一致,一致的前提下才赋予新的值x,此时返回true,否则返回false。
举例说明:10个线程分别竞争访问与修改Integer与AtomicInteger
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public class TestAtomicInteger {
public static void main(String[] args) {
TestAtomicInteger test = new TestAtomicInteger();
test.test();
}
private static int THREAD_COUNTER = 10;
private CountDownLatch countDownLatcher = new CountDownLatch(THREAD_COUNTER);
private Integer a = Integer.valueOf(0);
private AtomicInteger atomicA = new AtomicInteger(0);
private class CounterRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
// Integer
a++;
// AtomicInteger
atomicA.getAndIncrement();
}
countDownLatcher.countDown();
}
};
private void test() {
CounterRunnable r = new CounterRunnable();
for (int i = 0; i < THREAD_COUNTER; i++) {
Thread thread = new Thread(r);
thread.start();
}
try {
countDownLatcher.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("a: " + a);
System.out.println("atomicA: " + atomicA);
}
}
// Integer虽然为final类型,但是多线程环境下读写需要额外的同步措施才可以保证正确性 a: 6832 // AtomicInteger则提供了原子性的自增实现 atomicA: 10000
Integer多线程下自增操作,需要额外的同步措施来保证线程安全。
以下两种方式均可以得到正确的结果,只是同步范围不一样而已。
// 同步自增操作
synchronized (TestAtomicInteger.class) {
a++;
}
// 同步整个for语句
synchronized (TestAtomicInteger.class) {
for (int i = 0; i < 1000; i++) {
// Integer
a++;
}
}
2.总结
AtomicInteger的线程安全由两点保证:
- volatile关键字修饰value字段,保证value字段对各个线程的可见性;
- CAS操作保证了多线程环境下对数据修改的安全性。