diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..282fc6bed287fc2baf97d951b6f07c05d68dbbee --- /dev/null +++ b/README.md @@ -0,0 +1,155 @@ +# 用Unsafe实现AtomicInteger类 +**原理** +AtomicInteger可以在并发情况下达到原子化更新,避免使用了synchronized,而且性能非常高。 +![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/7fa0b413ccc4eebf79a7d3f4fa8ba5e6.png#pic_center) + +AtomicInteger的底层是用Unsafe来实现的,这里我们手写一个AtomicInteger类,并且测试一下。 +**测试例子** +启动 1000 个线程,每个线程做 -10 元 的操作,如果初始余额为 10000 那么正确的结果应当是 0。 +以下代码在JDK1.8通过测试。 +## 账户Account 类 +```java +interface Account { + // 获取余额 + Integer getBalance(); + + // 取款 + void withdraw(Integer amount); + + /** + * 方法内会启动 1000 个线程,每个线程做 -10 元 的操作 + * 如果初始余额为 10000 那么正确的结果应当是 0 + */ + static void demo(Account account) { + List 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 实现类 + +```java +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 类 + +```java +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; + } + +} +``` +## 测试 + +```java +public class Test { + public static void main(String[] args) { + Account account = new DiyAccount(10000); + Account.demo(account); + } +} +``` +输出 + +``` +0 cost: 65 ms +``` +## 其它——Unsafe工具类UnsafeAccessor +我们知道`Unsafe `的构造方法是私有的,也没有`get`方法可以获取对象,所以我们只能通过反射的方式来实例化`Unsafe` 对象。 + +```java +public final class Unsafe { + private static final Unsafe theUnsafe; + + private Unsafe() { + } + ... +} +``` + +所以 +```java +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; + } +} +``` \ No newline at end of file