欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

初识java atomic

程序员文章站 2022-10-18 12:41:42
2018-8-19 昨天看到java.util.concurrent.atomic相关的文章,之前有过留意但并未去了解,正好有空学习一下。本人理解atomic包是concurrent子包,当是为并发所用,拿int类型来说, int i=0; i++; i++并没有做同步写处理,当并发去写时,就可能出 ......

2018-8-19

  昨天看到java.util.concurrent.atomic相关的文章,之前有过留意但并未去了解,正好有空学习一下。本人理解atomic包是concurrent子包,当是为并发所用,拿int类型来说,

int i=0; i++; i++并没有做同步写处理,当并发去写时,就可能出现一个线程所写的结果被另外线程所写的结果覆盖,造成最终结果不符合预期,但是如果用synchronized修饰方法,

就是同步方法,与并发处理相冲突,atomic中的类型则可解决此问题,并发时,可理解为各线程尝试修改,不符合预期结果则更新数据重新尝试修改,可避免结果被覆盖情况。

  即可理解为synchronized严格同步为悲观锁,atomic为乐观锁,atomic中的类适合并发编程

以代码来展示:

初识java atomic
public class atomictest {

    
    public static int clienttotal=10000;
    public static int threadtotal=200;
    public static int count=0;
    public static atomicinteger atomiccount=new atomicinteger(0);
    
    public static void main(string[] args) {
        try {
            test();
        } catch (interruptedexception e) {
            e.printstacktrace();
        }
    }

    public static void test() throws interruptedexception {
        executorservice pool = executors.newcachedthreadpool();
        final semaphore semphore= new semaphore(threadtotal);
        final countdownlatch latch=new countdownlatch(clienttotal);
        for(int i=0;i<clienttotal;i++) {
            pool.execute(()->{
                try {
                    semphore.acquire();
                    add();
                    addatomic();
                    semphore.release();
                } catch (interruptedexception e) {
                    e.printstacktrace();
                }
                latch.countdown();
            });
        }
        latch.await();
        pool.shutdown();
        system.out.println("count--"+count);
        system.out.println("atomiccount--"+atomiccount);
    }
    public static void add() {
        count++;
    }
    public static void addatomic() {
        atomiccount.incrementandget();
    }
    
}
view code

结果:

count--9998
atomiccount--10000

结果中看出,count不符合预期,部分计算值被覆盖,比如执行一段时间后,当count=1300,线程thread5与线程thread6同时读到这个值,thread5运算写入count=1301,

thread6由于执行运算时count不是最新值,也随之写入count=1301,此时thread6把thread5结果覆盖了,本来两个线程执行完成预期是1302,真实完成后却是1301,

而atomiccount则符合预期。

查看atomicinteger源码:

初识java atomic
private volatile int value;
public final int incrementandget() {
        return unsafe.getandaddint(this, valueoffset, 1) + 1;
    }
public final int getandaddint(object o, long offset, int delta) {
        int v;
        do {
            v = getintvolatile(o, offset);
        } while (!compareandswapint(o, offset, v, v + delta));
        return v;
    }  
view code

从代码中可看出实现原理,private volatile int value;用volatile修饰value,这样每次写读写都是用最新的值,以下代码

do { 

  v = getintvolatile(o, offset);

} while (!compareandswapint(o, offset, v, v + delta));

即先获得最新的value值,然后比较运算后是否符合预期,符合则写入,不符合则返回false,又重新尝试,compareandswap即熟知的cas,此为原子操作,

即用volatile修饰符来保证最新值,用compareandswap方法来保证原子性。