初识java atomic
2018-8-19
昨天看到java.util.concurrent.atomic相关的文章,之前有过留意但并未去了解,正好有空学习一下。本人理解atomic包是concurrent子包,当是为并发所用,拿int类型来说,
int i=0; i++; i++并没有做同步写处理,当并发去写时,就可能出现一个线程所写的结果被另外线程所写的结果覆盖,造成最终结果不符合预期,但是如果用synchronized修饰方法,
就是同步方法,与并发处理相冲突,atomic中的类型则可解决此问题,并发时,可理解为各线程尝试修改,不符合预期结果则更新数据重新尝试修改,可避免结果被覆盖情况。
即可理解为synchronized严格同步为悲观锁,atomic为乐观锁,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(); } }
结果:
count--9998
atomiccount--10000
结果中看出,count不符合预期,部分计算值被覆盖,比如执行一段时间后,当count=1300,线程thread5与线程thread6同时读到这个值,thread5运算写入count=1301,
thread6由于执行运算时count不是最新值,也随之写入count=1301,此时thread6把thread5结果覆盖了,本来两个线程执行完成预期是1302,真实完成后却是1301,
而atomiccount则符合预期。
查看atomicinteger源码:
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; }
从代码中可看出实现原理,private volatile int value;用volatile修饰value,这样每次写读写都是用最新的值,以下代码
do {
v = getintvolatile(o, offset);
} while (!compareandswapint(o, offset, v, v + delta));
即先获得最新的value值,然后比较运算后是否符合预期,符合则写入,不符合则返回false,又重新尝试,compareandswap即熟知的cas,此为原子操作,
即用volatile修饰符来保证最新值,用compareandswap方法来保证原子性。