java并发:AtomicInteger 以及CAS无锁算法【转载】

1 AtomicInteger解析
众所周知,在多线程并发的情况下,对于成员变量,可能是线程不安全的;
一个很简单的例子,假设我存在两个线程,让一个整数自增1000次,那么最终的值应该是1000;但是多线程情况下并不能保证原子性;最终的结果极有可能不是1000;看如下的代码:
《java并发:AtomicInteger 以及CAS无锁算法【转载】》

package automic; public class AtomicIntegerTest extends Thread{ private Integer count=0; @Override public void run() { for(int i=1;i<=500;i++){ count++; } System.out.println("count的值是:"+ count); } public static void main(String[] args) { AtomicIntegerTest a=new AtomicIntegerTest(); Thread t1 = new Thread(a); Thread t2 = new Thread(a); t1.start(); t2.start(); } }

《java并发:AtomicInteger 以及CAS无锁算法【转载】》
最终的结果无论如何都是小于1000的,因为两个线程可能同时去修改了变量的值导致的;
使用AtomicInteger保证线程安全。AtomicInteger类,是一个对于变量可以进行原子性操作的类;核心是CAS无锁算法。
CAS算法是基于乐观锁的实现方法,在不需要锁的情况下,并且在并发量不高的情况下完成的原子性的操作。
主要原理是当一个线程去修改这个值的时候,会进入一个while循环,并且不断的尝试comparreAndSet()方法,也就是不断地比较内存值和期望值,如果相等就修改,不相等就返回false,当值修改完毕结束死循环;
对于上述的代码,我们可以将Integer修改为AutomicInteger,且看如下的代码:
《java并发:AtomicInteger 以及CAS无锁算法【转载】》

 import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerTest2 extends Thread{ /** * 这里使用了AtomicInteger类,这是一个对于变量可以进行原子性操作的类;核心是CAS无锁算法; * 下面两个构造器其中一个进行了值得初始化 * public AtomicInteger(int initialValue) { * value = initialValue; * } * public AtomicInteger() { * } */ private AtomicInteger count=new AtomicInteger(0); @Override public void run() { for(int i=1;i<=500;i++){ /** * getAndIncrement是以原子的方式给当前值加1 */ count.getAndIncrement(); } System.out.println("count的值是:"+ count); } public static void main(String[] args) { AtomicIntegerTest2 a=new AtomicIntegerTest2(); Thread t1 = new Thread(a); Thread t2 = new Thread(a); t1.start(); t2.start(); } }

《java并发:AtomicInteger 以及CAS无锁算法【转载】》
最终的结果是1000;
采用AtomicInteger可以保证数据的原子性操作,多线程并发的情况下是安全的;
对于线程的安全来说,是一个老生常谈的问题:做到线程安全,我们最直接的方法一般有两种:
    1> 同步锁或者同步代码块
    2> 互斥锁或者重入锁
其实上述的两种都是利用锁的方式来解决线程并发问题,而且都是悲观锁的方式;
synchrnoized在jdk1.6之后做了优化,在性能上和Lock锁处于相同的数量级的位置上;
synchnoized本身就具备了原子性操作;即锁的方式本身就保证了数据操作的原子性;
而CAS算法没有利用锁的技术;他如何实现的呢?
且看如下的源代码:
《java并发:AtomicInteger 以及CAS无锁算法【转载】》

public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; // setup to use Unsafe.compareAndSwapInt for updates private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; }

《java并发:AtomicInteger 以及CAS无锁算法【转载】》

 

① Unsafe是CAS的核心类,一切底层的具体实现由他来完成;
② valueOffset 变量在内存中地址的起始偏移量;
如下的静态代码块是完成变量的初始化;当JVM加载该类的时候就为这个变量在内存中开辟内存地址;它通过反射的手法获取字段value的值,而value的值使用了volatile去修饰,保证了内存的可见性(这点至关重要);但是volatile本身不可以保证操作的原子性;

 static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } }
private volatile int value;

 
再来看一看这个方法getAndIncrement();表示给特定的变量添加1;这个方法的源码如下:为了明晰原理,我这里使用的是jdk1.7
《java并发:AtomicInteger 以及CAS无锁算法【转载】》

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

《java并发:AtomicInteger 以及CAS无锁算法【转载】》

在看看jdk1.8的源码:

public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); }

使用了unsafe的方法,其实二者底层的实现方式都差不多:

进入一个for循环,不断的比较内存值和期望值,如果相等就修改,不相等就返回false;

《java并发:AtomicInteger 以及CAS无锁算法【转载】》

    /** * set()方法 ,设置一个值 */ public final void set(int newValue) { value = newValue; } /** * lazySet()方法,没有storeload屏障的set,出现于JDK1.6 */ public final void lazySet(int newValue) { unsafe.putOrderedInt(this, valueOffset, newValue); } /** * getAndSet()方法 原子性的获取并且设置值 */ public final int getAndSet(int newValue) { return unsafe.getAndSetInt(this, valueOffset, newValue); } /** * 如果当前值和内存值相等,那么进行更新 */ public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } /** * weak的CAS,也就是没有volatile语义的CAS,没有加入内存屏障 */ public final boolean weakCompareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } /** * 自增加,返回原来的值. */ public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 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; } /** * 阻塞式更新,并且对prev进行一个IntUnaryOperator操作运算 */ public final int updateAndGet(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return next; } /** * 阻塞式更新,并对prev和x,进行二元运算操作。于jdk1.8出现 */ public final int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction) { int prev, next; do { prev = get(); next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return prev; }

《java并发:AtomicInteger 以及CAS无锁算法【转载】》    
原文地址:
https://www.cnblogs.com/gosaint/p/9045494.html

    原文作者:java锁
    原文地址: https://www.cnblogs.com/expiator/p/9449298.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞