读书人

关于AbstractOwnableSynchronizer种解

发布时间: 2012-08-27 21:21:57 作者: rapoo

关于AbstractOwnableSynchronizer类解惑

今天刚看了一点Java并发编程实践,随手拿着Java源码分析了一下。

?

看到ReadWriteLock部分兴起,跟着源代码看到了ReentrantReadWriteLock,对其实现的读写分离锁原理非常好奇,平时都是基于如何使用,但是对其实现机制不甚了解,于是驱动自己看了看源码

?

大体上明白了其中的原理,就是设置了两个标识:

?

第一个exclusiveOwnerThread,标识线程是否是Write线程,如果有线程设置,则认为该线程为写线程,其它线程必须等待。

?

第二个标识是:state,该标识是读写线程会修改该值。

?

有点疑惑的是:

?

?

final boolean tryWriteLock() {            Thread current = Thread.currentThread();            int c = getState();            if (c != 0) {                int w = exclusiveCount(c);                if (w == 0 ||current != getExclusiveOwnerThread())                    return false;                if (w == MAX_COUNT)                    throw new Error("Maximum lock count exceeded");            }            if (!compareAndSetState(c, c + 1))                return false;            setExclusiveOwnerThread(current);            return true;        }
?

?

?该方法中w == 0 ||current != getExclusiveOwnerThread()?这句代码十分关键,这就是这句代码主导了不使用同步锁也能保证判断的正确性。

?

首先分析有两种线程有可能会调用该方法:第一种写线程,第二种读线程

?

关键点:一个线程对一个变量的前后读写,在本线程是始终可以看到结果的。

?

如果是写线程调用的时候,那么肯定是该写线程首先对exclusiveOwnerThread进行了赋值写入(获取锁定),那么在同一个线程中赋值是可见的,也就是在接下来的释放过程中,并不需要内存同步。

?

如果是读线程调用的时候,唯一有可能发生意外的情况是:

该读线程是由前面的写线程转变而来,可能会想到current == getExclusiveOwnerThread()成立的情况,但是这种情况是不存在的,因为要从写线程转变成读线程,首先就是得有释放写锁的过程(如果没有锁的释放过程,那么程序逻辑本身就存在错误了),也就是有了setExclusiveOwnerThread(null)的过程,那么转变过后的读线程应该看到的null或者是锁被释放过后其它线程设置的值,而非以前本线程在身为写线程时数值。

?

注意区别:读线程和写线程中获取读锁的区别,这里的读线程是指只获取读锁的线程,与写线程中先获取写锁,然后再获取读锁是有区别的。

?

如果该线程是从上一次调用的写线程转化而来,那么这次看到的自己的内存exclusiveOwnerThread应该是null,一定不会是自己。那就保证 if (w == 0 ||current != getExclusiveOwnerThread())正确性了。

?

一句话就是:如果是写线程那么看到的exclusiveOwnerThread一定是自己,如果是读线程那么看到的exclusiveOwnerThread一定不是自己!

?

那么有可能读到不是最新的exclusiveOwnerThread值已经不重要!重要的是保证了如果是读线程,那么current != getExclusiveOwnerThread()一定正确!

读书人网 >编程

热点推荐