Java高效并发(十二)----非阻塞同步方案实现线程安全

前面我们讲了互斥同步和无同步方法实现线程安全,其中互斥同步也叫阻塞同步,接下来学习的是非阻塞同步实现线程安全

 非阻塞同步

互斥同步是一种悲观锁,认为竞争总是会发生,那么非阻塞同步就是一种基于冲突检测的乐观并发策略。这里就是用到之前说过的CAS操作检测冲突,如果没有冲突,CAS操作成功就继续执行操作,如果有冲突,就采取其他补救措施,一般是不断尝试CAS操作直到成功为止。这种乐观的并发策略的许多实现都不需要把线程挂起,所以叫做非阻塞同步方法。

非阻塞同步方法要求检测冲突和操作是原子操作。在J.U.C并发包中有一个atomic包,里面就实现了一些直接使用CAS操作的线程安全的类型,也就是这些类型保证了检测冲突和操作是原子性的。最常用的就是AtomicInteger类。

 AtomicInteger类

在这篇中https://blog.csdn.net/wangdongli_1993/article/details/81202561我们说过使用volatile修饰int型变量i,多个线程同时进行i++操作,这样不可以实现线程安全。但是如果我们把i定义成AtomicInteger类型的,使用AtomicInteger类中的incrementAndGet()方法来自增就是线程安全的。主要就是因为int型变量i++操作不是原子操作,而incrementAndGet()却通过不断的CAS操作实现了自增的原子性。接下来我们通过源码来分析这个类。下面是这个类中的一些方法

然后我们截取部分源码, 最下面有一个volatile修饰的int变量value,它就是整数当前的值,还有一个long类型的valueOffset,塔代表了偏移量,指正里面的概念通过这个偏移量找到value

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;

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

    private volatile int value;

    /**
     * Creates a new AtomicInteger with the given initial value.
     *
     * @param initialValue the initial value
     */
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

 首先我们参看incrementAndGet()方法的源码,其他方法类似

 这个在jdk1.7和jdk1.8的实现方式是不一样的。

先看jdk1.8的实现,是调用了unsafe的方法。

上面可以看到这是一个位于sun.misc.Unsafe的实例变量,这个一个Native方法,我们看到 unsafe = Unsafe.getUnsafe();但是getUnsafe()方法我们自己是不可以使用的,调用这个方法之前JVM会检查调用这个方法的类,如果这个类的classLoader不为null,就抛出字符串“unsafe”的异常,也就是只能是有Bootstrap类加载器来加载的

 也就是说它的CAS操作是Unsafe类来实现的。

而在jdk1.7中,incrementAndGet的源码如下:一直做CAS操作直到成功返回值,但是CAS操作都是unsafe提供的

猜你喜欢

转载自blog.csdn.net/wangdongli_1993/article/details/81288144