【Java8源码分析】locks包-ReentrantLock
来源:互联网 发布:咬人猫年龄 知乎 编辑:程序博客网 时间:2024/05/24 06:34
转载请注明出处:http://blog.csdn.net/linxdcn/article/details/72850375
1 辅助内部类
在ReetrantLock内部基于AQS类实现了一个抽象类Sync同步器,对于AQS不熟悉的,可以看看这篇文章:AbstractQueuedSynchronizer同步器。基于Sync还实现了公平锁和非公平锁:
- 公平锁
- 线程按照他们发出请求的顺序获取锁
- 如果有另一个线程持有锁或者有其他线程在等待队列中等待这个所,那么新发出的请求的线程将被放入到队列中。
- 非公平锁
- 当一个线程请求非公平锁时,如果在发出请求的同时该锁变成可用状态,那么这个线程可能会跳过队列中所有的等待线程而获得锁
- 非公平锁上,只有当锁被某个线程持有时,新发出请求的线程才会被放入队列中
//抽象同步器Sync继承AQS,子类可以非公平或者公平锁abstract static class Sync extends AbstractQueuedSynchronizer { abstract void lock(); // 非公平锁的尝试获取 final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { // 跟公平锁获取的区别时,这里少了判断队列是否为空的函数hasQueuedPredecessors // 即不管排队队列是否为空,该线程都将直接尝试获取锁 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } // 以下这个函数实现了重入锁 else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }}//非公平锁的同步器static final class NonfairSync extends Sync { final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }}// 公平锁的同步器static final class FairSync extends Sync { final void lock() { acquire(1); } protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }}
2 主要方法
ReentrantLock的方法源码比较简单,主要是委托给Sync同步器实现。
//构造函数,默认使用非公平锁同步器public ReentrantLock() { sync = new NonfairSync();}public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync();}public void lock() { sync.lock();}public void unlock() { sync.release(1);}// 实现了条件变量public Condition newCondition() { return sync.newCondition();}
3 条件变量
条件变量是实现了Java中的Condition接口的类,其中Condition中的await、signal、signalAll方法与Object中的wait、notify、notifyAll类似。
假设现在我们有三个线程A、B、C,申请了一个ReetrantLock,以及两个条件变量,如下代码,下面举例说明Condition如何工作
Lock lock = new ReentrantLock();Condition conditionX = lock.newCondition();Condition conditionY = lock.newCondition();
初始状态
假设已经有一个线程获取的了lock,然后线程A、B、C依次获取lock,状态图如下:
Step 1
线程A、B分别调用了conditionX.await()
,源码如下
public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); // 把等待线程包装为Node Node node = addConditionWaiter(); // 释放锁 int savedState = fullyRelease(node); int interruptMode = 0; while (!isOnSyncQueue(node)) { // 线程在此挂起 LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } // 当收到signal通知后,线程会继续,抢占锁 if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); // 如果抢占不成功,线程继续挂起 if (interruptMode != 0) reportInterruptAfterWait(interruptMode);}//在等待队列中新建一个Nodeprivate Node addConditionWaiter() { Node t = lastWaiter; if (t != null && t.waitStatus != Node.CONDITION) { unlinkCancelledWaiters(); t = lastWaiter; } Node node = new Node(Thread.currentThread(), Node.CONDITION); if (t == null) firstWaiter = node; else t.nextWaiter = node; lastWaiter = node; return node;}
线程A、B均在函数LockSupport.park(this)
处被挂起,等待通知,目前的状态图如下:
Step 2
线程C获得锁,执行。当C执行完后,调用signal
通知await
的线程
// 将一个等待时间最长的waitQueue的Node移到lockQueuepublic final void signal() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignal(first);}private void doSignal(Node first) { do { if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; } while (!transferForSignal(first) && (first = firstWaiter) != null);}final boolean transferForSignal(Node node) { if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; Node p = enq(node); int ws = p.waitStatus; if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true;}
4 总结
(1)synchronized关键字无法中断一个正在等候获得锁的线程,也无法通过轮询得到锁;ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,但是添加了类似轮询锁、定时锁等候和可中断锁等候的一些特性。
(2)根类 Object 包含某些特殊的方法,用来在线程的 wait() 、 notify() 和 notifyAll() 之间进行通信;Lock 框架包含了对 wait 和 notify 的概括,这个概括叫作 条件(Condition),对于指定的 Lock ,可以有不止一个条件变量与它关联。
(3)synchronized的优点:使用 synchronized 的时候,不可能忘记释放锁;在退出 synchronized 块时,JVM 会做这件事;当 JVM 用 synchronized 管理锁定请求和释放时,JVM 在生成线程转储时能够包括锁定信息。这些对调试非常有价值,因为它们能标识死锁或者其他异常行为的来源
(4)java.util.concurrent.lock 中的锁定类是用于高级用户和高级情况的工具 。一般来说,除非您对 Lock 的某个高级特性有明确的需要,或者有明确的证据(而不是仅仅是怀疑)表明在特定情况下,同步已经成为可伸缩性的瓶颈,否则还是应当继续使用 synchronized。
参考
https://www.ibm.com/developerworks/cn/java/j-jtp10264/index.html
转载请注明出处:http://blog.csdn.net/linxdcn/article/details/72850375
- 【Java8源码分析】locks包-ReentrantLock
- 【Java8源码分析】locks包-AbstractQueuedSynchronizer同步器
- 【Java8源码分析】locks包-ReentrantReadWriteLock
- JUC源码分析9-locks-ReentrantLock
- java.util.concurrent.locks.ReentrantLock 源码剖析
- 【Java8源码分析】并发包-AtomicInteger
- 【Java8源码分析】并发包-CopyOnWriteArrayList
- 【Java8源码分析】并发包-Semaphore
- 【Java8源码分析】并发包-CountDownLatch
- 【Java8源码分析】并发包-CyclicBarrier
- 【Java8源码分析】NIO包-FileChannel
- 【Java8源码分析】NIO包-Selector选择器
- java.util.concurrent.locks.ReentrantLock重入锁源码解析
- ReentrantLock 源码分析
- java ReentrantLock源码分析
- ReentrantLock源码分析
- JUC - ReentrantLock 源码分析
- ReentrantLock 源码分析
- HTML内部文本的基本结构及注释
- react-native使用Swiper在安卓上不显示
- C#图像处理(剪切、合成、缩略)
- mac 下配置maven
- LC Binary-Search summary
- 【Java8源码分析】locks包-ReentrantLock
- Python-异常处理
- java的各种知识点(三)
- 进程资源
- 高新面试系列 性格篇
- Linux install googletest
- Spring 4 官方文档学习(①)Web MVC 框架之异常处理
- 游戏编程中的人工智能 补
- SQL之case when then用法详解