无锁的线程安全整数-AtomicInteger

JDK并发包中有一个atomic包,里面实现了一些直接使用CAS操作的线程安全的类型。

其中,最常用的一个类,应该就是AtomicInteger。你可以把它看做是一个整数。他与Integer不同的是,它是可变的,线程安全的。对其的任何操作都是CAS指令执行的。

 
    // 取得当前值
    public final int get() {
        return value;
    }

    // 设置当前值
    public final void set(int newValue) {
        value = newValue;
    }
    // 设置新值,并返回旧值
    public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }
    // 如果当前值为expect,则设置为u
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
    // 当前值+1,返回旧值
     public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
    // 当前值-1,返回旧值
    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }
    // 当前值增加delta,返回旧值
    public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }
    // 当前值+1,返回新值
     public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }
    // 当前值-1,返回新值
    public final int decrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
    }
    // 当前值增加delta,返回新值
    public final int addAndGet(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
    }

就内部实现来说,AtomicInteger中保存一个核心字段: private volatile int value;

它就代表了AtomicInteger的当前实际取值。此外还有一个: private static final long valueoffset;

它保存着value字段在AtomicInteger对象中的偏移量。后面你会看到,这个偏移量是实现AtomicInteger的关键。

   
    static AtomicInteger atomicInteger = new AtomicInteger();

    public static void main(String[] args) {
        AtomicTest atomicTest = new AtomicTest();
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread t = new Thread(r);
                        t.setDaemon(true);
                        System.out.println("create " + t);
                        return t;
                    }
                });
        for (int i = 0; i < 5; i++) {
            poolExecutor.execute(atomicTest);
        }

        try {
            Thread.sleep(80000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(atomicInteger);
    }

     public static class AtomicTest implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                atomicInteger.incrementAndGet();
            }
        }
    }

上段代码执行完毕,结果是50000,如果是线程不安全的话,得出的结果肯定要比50000小。

我们来分析一下incrementAndGet()的内部实现(JDK1.7中)。

public final int incrementAndGet(){
    
    for(;;){
        int current = get();
        int next = current + 1;
        if(compareAndSet(current,next)){
          return next;  
        }
    }
    
}

因为CAS操作不是一定成功的,所以进行无限循环。+1后得到新的值 next,使用 compareAndSet将新值成功写入之后,return;成功的写入条件是,在写入的时刻,当前的值,应该要等于刚刚取得的current。如果不是这样,说明被别的线程修改过。要下一次尝试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值