今天看了下传说中线程安全的AtomicInteger的源码,总共只有不到300行,其中关键的代码就更少了,主要有以下几段:安全
1.value值设为volatile,保证其内存可见性ide
private volatile int value;
值得注意的是,volatile关键字只是一种轻量级的同步方法,用来保证变量的内存可见性,可是并不能代替synchronizied。简单举个例子:测试
static volatile int count = 0; public static void main(String[] args) { for(int i=0;i<10000;i++){ new Thread(new Runnable() { @Override public void run() { count++; } }).start(); } System.out.println("count:"+count);
最终输出结果并不必定是指望的10000,而每每是一个比10000小的数字。缘由是可能多个线程同时从主内存中读取到最新的conut值,而后在各自的工做内存中执行了++操做,再往主存中同步的时候,就会写入一样的值,至关于一次++操做失效。this
2.接着看源码,getAndSet(int newValue)方法spa
/** * Atomically sets to the given value and returns the old value. * * @param newValue the new value * @return the previous value */ public final int getAndSet(int newValue) { for (;;) { int current = get(); if (compareAndSet(current, newValue)) return current; } }
方法中并无synchronizied或者volatile关键字,那到底是如何实现线程安全的呢?关键的方法在于compareAndSet(current,newValue),源码以下:线程
public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
调用了unsafe的compareAndSwapInt方法,是利用了大名鼎鼎的CAS来实现的原子操做,虽然CAS也用到了排他锁,可是比起synchronized,效率要高的多。code
3.getAndIncrement()方法blog
/** * Atomically increments by one the current value. * * @return the previous value */ public final int getAndIncrement() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return current; } }
可见跟getAndSet方法大同小异,首先get()取出当前的value值,而后+1,紧接着仍是调用了compareAndSet方法,看next和预期值是否相同,不相同则进入下一轮循环。内存
4.incrementAndGet()方法rem
/** * Atomically increments by one the current value. * * @return the updated value */ public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } }
与getAndIncrement相比,只是最后一行代码有差异,一个是返回current,一个是返回next,我的理解就是利用CAS的原子操做,实现了线程安全的 i++和 ++i 。
其余的方法也都是相似的,到底层调用unsafe包的CAS原子操做实现,很少说了,下面是作了一个测试:
public static void main(String[] args) { final AtomicInteger integer = new AtomicInteger(0); for (int i = 0; i < 10000; i++) { new Thread(new Runnable() { @Override public void run() { integer.getAndIncrement(); } }).start(); } System.out.println(integer.get());
运行,输出10000没问题,再运行几遍,9999,9998都出现了,什么状况?说好的线程安全呢?百思不得其解,最后求助大神,给出答案,原来循环中的线程尚未执行完,就执行了打印的语句。修改代码以下:
public static void main(String[] args) { final AtomicInteger integer = new AtomicInteger(0); for (int i = 0; i < 10000; i++) { new Thread(new Runnable() { @Override public void run() { integer.getAndIncrement(); } }).start(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(integer.get()); }
OK,再也没有出现以前的状况,可见AtomicInteger确实是能保证线程安全的,不过因为是一个无限的for循环里面,不断的进行比较、更新操做,所以,能够想象,在线程数量很是大的状况下,运行速度会比较慢。