耐心看完的你或多或少会有收获!html
Java并发的核心就是 java.util.concurrent 包,而 j.u.c 的核心是AbstractQueuedSynchronizer
抽象队列同步器,简称 AQS,一些锁啊!信号量啊!循环屏障啊!都是基于AQS。而 AQS 又是基于Unsafe
的一系列compareAndSwap
,因此理解了这块,并发再也不是问题!java
但愿你已经了解了 Java内存模型c++
先解释下何为compareAndSwap
,就拿AtomicInteger
来举例了:安全
// 实际操做的值 private volatile int value; // value 的偏移量 由于 int 是32位,知道首部地址就能够了 private static final long valueOffset; // 静态初始化块,经过虚拟机提供的接口,得到 valueOffset = 12 // 不论你实例化多少个 AtomicInteger 对象,这些对象尽管指向不一样的堆内存,可是结构都是同样的 // 因此初始化一次就行了 static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } // 只是个封装方法,起做用的代码并不在这 // 值得注意的是显式的 this 和第三个参数 1 public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } // 如下是 Unsafe 类 能够直接访问内存地址,相似指针,因此不安全 // o 就是 getAndIncrement()传入的 this,也就是 AtomicInteger 实例对象 // offset 内存首部偏移量 // delta 就是那个 1 // 应该是希腊字母 δ /'deltə/ delta 变化量,化学反应中的加热,屈光度,一元二次方程中的判别式 // 佩服 public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!compareAndSwapInt(o, offset, v, v + delta)); return v; } // 从堆内存获取最新的 value // 若是不明白,能够先了解下 JMM 和 volatile public native int getIntVolatile(Object o, long offset); // expected 就是这个 v = getIntVolatile(o, offset); // 意思就是,我给你这个最新的 value,它要是如今 在内存中仍是这个值 那你就返回 true,而且把这块内存上值更新为 x // 否则的话,我就一直 while (!compareAndSwapInt(o, offset, v, v + delta)); // 至关于自旋锁 活锁,不要被高大上的术语吓到 就是活的循环,不会像死锁那样线程 hang 住 public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);
知道了CAS
就能够进一步的说说ReentrantLock
, 若是未曾了解Java
对象结构,建议先了解下 Java 对象的内存结构多线程
AQS
的几个子类,因为方法和功能不一,在同步处理的细节上可能不同。可是,原理都是同样的,离不开上述的CAS
并发
// 我先简单解释一下 synchronized 工做原理 首先它含有 monitorenter 和 monitorexit 两条指令 // Java 中的每一个对象都有本身的 Monitor(由HotSpot c++ 实现) // 当某个线程进入加锁的代码(实际上应该是拿到被加锁的对象在内存的引用地址) // 会执行 monitorenter 而后将 monitor 置为1,当其它线程访问该内存时,发现 monitor 不为 0 // 因此其它线程没法得到 monitor,直到占有 monitor 的线程执行 monitorexit 退出将 monitor 减 1 // 若是占有 monitor 的线程重复进入,monitor 是能够一直累加的(可重入锁,例如经过递归或方法互调) // 了解了 synchronized 基本的工做原理,就会明白为何会有诸如 nonfairTryAcquire(1) release(1) 的方法 // 这是 AbstractQueuedSynchronizer 类中的字段 // 由于 ReentrantLock 中的内部类 Sync 继承于 AQS // The synchronization state private volatile int state; // tryLock why ? // 由于不一样于 synchronized 的悲观(我才无论你是否是并发,多线程,声明了,我就加锁) // 因此 ReentrantLock 我先 try 一 try 吧!万一不是多线程并发呢!🤣 public boolean tryLock() { // 加锁 加 1 return sync.nonfairTryAcquire(1); } public void unlock() { // 释放锁 减 1 sync.release(1); } final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); // 0 的话 说明没有线程占有 // 能够得到锁 if (c == 0) { // 这个和上面的 AtomicInteger 同样 if (compareAndSetState(0, acquires)) { // 设置当前占有锁的线程 setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; // 看见没,锁的计数有可能会有问题 // 由于锁的可重入,一直累加,指不定就加到 int 上限转负数了 if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); // 不小于 0 更新 state setState(nextc); return true; } return false; } // AbstractOwnableSynchronizer 类 // The current owner of exclusive mode synchronization. // 排它锁 独占锁 写锁 都一个意思 锁的当前持有线程 private transient Thread exclusiveOwnerThread;
Unsafe monitor 的相关方法,已弃用ui
/** Lock the object. It must get unlocked via {@link #monitorExit}. */ @Deprecated public native void monitorEnter(Object o); /** * Unlock the object. It must have been locked via {@link * #monitorEnter}. */ @Deprecated public native void monitorExit(Object o); /** * Tries to lock the object. Returns true or false to indicate * whether the lock succeeded. If it did, the object must be * unlocked via {@link #monitorExit}. */ @Deprecated public native boolean tryMonitorEnter(Object o);
如下为 hotspot c++ 源码的一部分代码,想追根溯源的能够了解下 hotspot 源码(页面左侧提供下载和浏览的连接)this
// Enter support void ObjectMonitor::enter(TRAPS) { // The following code is ordered to check the most common cases first // and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors. Thread * const Self = THREAD; void * cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL); if (cur == NULL) { // Either ASSERT _recursions == 0 or explicitly set _recursions = 0. assert(_recursions == 0, "invariant"); assert(_owner == Self, "invariant"); return; } if (cur == Self) { // TODO-FIXME: check for integer overflow! BUGID 6557169. // 看来出现过 count overflow bug _recursions++; // recursion 递归说明了可重入 return; } // 省略 } void ObjectMonitor::exit(bool not_suspended, TRAPS) { Thread * const Self = THREAD; if (THREAD != _owner) { if (THREAD->is_lock_owned((address) _owner)) { // Transmute _owner from a BasicLock pointer to a Thread address. // We don't need to hold _mutex for this transition. // Non-null to Non-null is safe as long as all readers can // tolerate either flavor. assert(_recursions == 0, "invariant"); _owner = THREAD; _recursions = 0; } else { // Apparent unbalanced locking ... // Naively we'd like to throw IllegalMonitorStateException. // As a practical matter we can neither allocate nor throw an // exception as ::exit() can be called from leaf routines. // see x86_32.ad Fast_Unlock() and the I1 and I2 properties. // Upon deeper reflection, however, in a properly run JVM the only // way we should encounter this situation is in the presence of // unbalanced JNI locking. TODO: CheckJNICalls. // See also: CR4414101 TEVENT(Exit - Throw IMSX); assert(false, "Non-balanced monitor enter/exit! Likely JNI locking"); return; } } if (_recursions != 0) { _recursions--; // this is simple recursive enter TEVENT(Inflated exit - recursive); return; } // 省略 }
Doug Lea 真正的大师,从他的代码中能够看出对于细节的处理与把控,以及对于我等代码阅读者的友好spa
大道至简,谁能想到 Java 的并发支持是基于一些加 1 减 1 的运算.net
synchronized
的 Monitor 和各类锁的 tryAcquire(1) tryRelease(1)
是否是很像🤣
若是有帮助你理解并发,那么你也能够再结合源码好好感觉下,请注意tryAcquire(1) tryRelease(1)
这两种方法(方法名或参数可能略有不一样)