先看个代码
如上图,声明一个对象V ,内含increase方法对value++,getValue 获取Value的值,代码中创建一个线程1 ,在内部循环1000W次,调用increase,主线程也循环1000W次调用increase,最后打印结果, 按道理,value初始值为0,最后的结果应该是 2000W ,但我们输出的结果显然不是,证明我们的代码是有问题的,看下increase 方法,如下图,在并发的时候会产生线程安全问题的,怎麽解决这个问题呢?有人很快想到了对increase方法加锁,一定是可行的,我们先看下
加锁后的执行结果是没问题的,这里画张图说下synchronized 加锁的原理
如下图,JDK1.6之前synchronized 是互斥锁,加锁实际上是对 this 对象的monitor进行加锁,多线程竞争时,抢不到锁的线程2,3 会进入队列等待线程1释放锁; JDK1.6 对synchronized 进行的优化归根结底就是减少了锁竞争,通过偏向锁,自旋等方式避免用户态和内核态的频繁切换.
那么,除了加锁还有哪些方法?第二种方法就是原子操作,就是大家都熟悉的AtomicInteger,我们改造一下代码运行一下,看下结果:
聊到这里就顺便说一下AtomicInteger 保证原子操作的原理,无论是JDK1.7还是1.8 底层都是通过自旋+CAS的方式实现的,
1.7源码
public final int incrementAndGet() {
//自旋锁
for (;;) {
//获取volatitle修饰的变量,最新的主存值
int current = get();
//理论上自增值
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
1.8源码
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
public final int getAndAddInt(Object obj, long valueOffset, int delta) {
int expect;
//自旋
do {
//获取主存的值
expect = this.getIntVolatile(obj, valueOffset);
//CAS操作
} while(!this.compareAndSwapInt(obj, valueOffset, expect, expect + delta));
//返回旧值
return expect;
}