Implement AtomicInteger class with Unsafe
Principle
AtomicInteger can achieve atomic updates under concurrent conditions, avoiding the use of synchronized, and the performance is very high.
The bottom layer of AtomicInteger is implemented with Unsafe. Here we hand-write an AtomicInteger class and test it.
Test example
Start 1000 threads, and each thread does -10 yuan operation. If the initial balance is 10000 then the correct result should be 0.
The following code passed the test in JDK1.8.
Account class
interface Account {
// 获取余额
Integer getBalance();
// 取款
void withdraw(Integer amount);
/**
* 方法内会启动 1000 个线程,每个线程做 -10 元 的操作
* 如果初始余额为 10000 那么正确的结果应当是 0
*/
static void demo(Account account) {
List<Thread> ts = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
ts.add(new Thread(() -> {
account.withdraw(10);
}));
}
long start = System.nanoTime();
ts.forEach(Thread::start);
ts.forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
long end = System.nanoTime();
System.out.println(account.getBalance()
+ " cost: " + (end-start)/1000_000 + " ms");
}
}
Account implementation class
class DiyAccount implements Account {
private DiyAtomicInteger balance;
public DiyAccount(int balance) {
this.balance = new DiyAtomicInteger(balance);
}
@Override
public Integer getBalance() {
return balance.getValue();
}
@Override
public void withdraw(Integer amount) {
balance.decrement(amount);
}
}
DiyAtomicInteger class
class DiyAtomicInteger {
private volatile int value; //实例操作的变量
private static final long valueOffset;//偏移量
private static final Unsafe UNSAFE;// unsafe实例对象
static {
UNSAFE = UnsafeAccessor.getUnsafe();
try {
valueOffset = UNSAFE.objectFieldOffset(DiyAtomicInteger.class.getDeclaredField("value"));
} catch (NoSuchFieldException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public int getValue() {
return value;
}
public void decrement(int amount) {
while (true) {
int prev = this.value;
int next = prev - amount;
if (UNSAFE.compareAndSwapInt(this, valueOffset, prev, next)) {
break;
}
}
}
public DiyAtomicInteger(int value) {
this.value = value;
}
}
test
public class Test {
public static void main(String[] args) {
Account account = new DiyAccount(10000);
Account.demo(account);
}
}
Output
0 cost: 65 ms
Other-Unsafe tool class UnsafeAccessor
Unsafe
The construction method we know is private, and there is no get
way to get the object, so we can only instantiate the Unsafe
object through reflection .
public final class Unsafe {
private static final Unsafe theUnsafe;
private Unsafe() {
}
...
}
and so
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class UnsafeAccessor {
private static final Unsafe unsafe;
static {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = (Unsafe) theUnsafe.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new Error(e);
}
}
public static Unsafe getUnsafe() {
return unsafe;
}
}
Project code