jdk 源码系列之ReentrantLock

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最近将 "},{"type":"text","marks":[{"type":"strong"}],"text":"ReentrantLock"},{"type":"text","text":" 学了一遍同时也把源码读了一遍,记录下学习的过程 "}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"JDK 源码系列"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://blog.sincehub.cn/2020/09/29/jdk-StringBuilder-StringBuffer/","title":null},"content":[{"type":"text","text":"jdk 源码系列之StringBuilder、StringBuffer"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://blog.sincehub.cn/2020/10/31/jdk-HashMap/","title":null},"content":[{"type":"text","text":"jdk 源码系列之HashMap"}]}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"使用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用锁机制,来保障线程安全"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Lock lock = new ReentrantLock();\n\n lock.lock();\n\n try {\n // 受此锁保护的资源块\n } finally {\n lock.unlock();\n }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"或者你可以使用 tryLock() 方法,在多线程中,当一个线程释放锁的时候,就尝试去获取锁。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Lock lock = new ReentrantLock();\n if (lock.tryLock()) {\n try {\n // 受此锁保护的资源块\n } finally {\n lock.unlock();\n }\n } else {\n // 进行其他操作,未被锁保护\n }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这种方法,在确保获取锁的时候才会解锁,并且在未获锁时不会尝试去解锁。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果尝试去获取锁的时候太长,也可以给获取锁的这个过程加上时间,超时则直接中断线程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public static void main(String[] args) throws InterruptedException {\n Lock lock = new ReentrantLock();\n if (lock.tryLock(5, TimeUnit.SECONDS)) {\n try {\n // manipulate protected state\n\n } \n finally {\n lock.unlock();\n }\n } else {\n // perform alternative actions\n }\n\n }\n\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果希望当前锁的模块不是立刻执行,也可以调用 await 机制"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"Lock lock = new ReentrantLock();\n lock.lock();\n try {\n // manipulate protected state\n lock.newCondition().await(5, TimeUnit.SECONDS);\n }\n finally {\n lock.unlock();\n }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有时候,当遇到过长的业务流程,导致持有的时间太长了,可以考虑打断锁的机制,释放锁。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Lock lock = new ReentrantLock();\n lock.lock();\n try {\n // manipulate protected state\n long startTime = System.currentTimeMillis();\n long endTime = System.currentTimeMillis();\n if (endTime - startTime > 10) {\n lock.lockInterruptibly();\n try {\n } finally {\n lock.unlock();\n }\n }\n\n lock.newCondition().await(5, TimeUnit.SECONDS);\n }\n finally {\n lock.unlock();\n }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"应用场景比较"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/bb/bbca72cf9fb58fb4373554a908369d91.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"源码"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先看类"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class ReentrantLock implements Lock, java.io.Serializable {\n private static final long serialVersionUID = 7373984872572414699L;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"向上继承了 "},{"type":"text","marks":[{"type":"strong"}],"text":"Lock"},{"type":"text","text":" 接口,以及 "},{"type":"text","marks":[{"type":"strong"}],"text":"Serializable"},{"type":"text","text":",都是实现了 "},{"type":"text","marks":[{"type":"strong"}],"text":"Lock"},{"type":"text","text":" 的方法。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"void lock() 获取锁"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"void lockInterruptibly() 中断锁机制"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"boolean tryLock() 其他线程有释放锁,才调用获取锁"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"boolean tryLock(long time, TimeUnit unit) 给定时间内线程是空闲时间,且其他线程有释放锁,才调用获取锁"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"void unlock() 释放锁"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Condition newCondition() 给锁绑定条件"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"实例化锁"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Lock lock = new ReentrantLock();\n\nLock lock1 = new ReentrantLock(false);\n\nLock lock2 = new ReentrantLock(true);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这里,有两个构造,一个是无参构造,一个是传入布尔值。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * Creates an instance of {@code ReentrantLock}.\n * This is equivalent to using {@code ReentrantLock(false)}.\n */\n public ReentrantLock() {\n // 创建一个非公平锁\n sync = new NonfairSync();\n }\n\n /**\n * Creates an instance of {@code ReentrantLock} with the\n * given fairness policy.\n *\n * @param fair {@code true} if this lock should use a fair ordering policy\n */\n public ReentrantLock(boolean fair) {\n // true 公平锁 false 非公平锁\n sync = fair ? new FairSync() : new NonfairSync();\n }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这里默认是构造一个非公平锁,也可以直接设置创建什么类型锁,比如公平锁、非公平锁。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们先看看公平锁。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * Sync object for fair locks\n */\n static final class FairSync extends Sync {\n private static final long serialVersionUID = -3000897897090466540L;\n\n final void lock() {\n // 当使用 lock.lock() 的时候调到 同时传入1\n acquire(1);\n }\n\n /**\n * Fair version of tryAcquire. Don't grant access unless\n * recursive call or no waiters or is first.\n */\n // 这里 acquires = 1指的是 上锁的状态 0则是未上锁\n protected final boolean tryAcquire(int acquires) {\n // 获取当前线程对象\n final Thread current = Thread.currentThread();\n // 是否上锁,首次默认是0\n int c = getState();\n if (c == 0) {\n // hasQueuedPredecessors 是否是当前线程,使用了双向链表的数据结构,做一个 queue,这里的意思大概是到了这个线程可以加锁了。不用排队了\n if (!hasQueuedPredecessors() &&\n // CAS 比较后修改成功\n compareAndSetState(0, acquires)) {\n // 将当前线程设置成独占线程\n setExclusiveOwnerThread(current);\n // 获取锁成功\n return true;\n }\n }\n // 独占线程\n else if (current == getExclusiveOwnerThread()) {\n // nextc = 1\n int nextc = c + acquires;\n if (nextc < 0)\n throw new Error(\"Maximum lock count exceeded\");\n // 同步锁的状态 = 1\n setState(nextc);\n return true;\n }\n // 其他线程则未获取到锁\n return false;\n }\n }\n\n /**\n * Acquires in exclusive mode, ignoring interrupts. Implemented\n * by invoking at least once {@link #tryAcquire},\n * returning on success. Otherwise the thread is queued, possibly\n * repeatedly blocking and unblocking, invoking {@link\n * #tryAcquire} until success. This method can be used\n * to implement method {@link Lock#lock}.\n *\n * @param arg the acquire argument. This value is conveyed to\n * {@link #tryAcquire} but is otherwise uninterpreted and\n * can represent anything you like.\n */\n public final void acquire(int arg) {\n // 尝试上锁\n if (!tryAcquire(arg) &&\n // 先将线程当前线程添加进队列最后一个,然后在判断是否到他上锁了\n acquireQueued(addWaiter(Node.EXCLUSIVE), arg))\n // 没有则直接打断线程\n selfInterrupt();\n }\n\n\n /**\n * Acquires in exclusive uninterruptible mode for thread already in\n * queue. Used by condition wait methods as well as acquire.\n *\n * @param node the node\n * @param arg the acquire argument\n * @return {@code true} if interrupted while waiting\n */\n // 持有锁的队列里面的线程\n final boolean acquireQueued(final Node node, int arg) {\n boolean failed = true;\n try {\n boolean interrupted = false;\n // 一个死循环你判断里面当前谁获得锁\n for (;;) {\n // 指向下一个节点\n final Node p = node.predecessor();\n // 队列的第一个,且获取锁,将当前线程变成独占线程\n if (p == head && tryAcquire(arg)) {\n setHead(node);\n p.next = null; // help GC\n failed = false;\n // 如果获得到锁,则不需要打断当前线程返回一个 false\n return interrupted;\n }\n // 线程阻塞了\n if (shouldParkAfterFailedAcquire(p, node) &&\n parkAndCheckInterrupt())\n // 中断获取锁的机制\n interrupted = true;\n }\n } finally {\n // 如果获得到锁 则不需要取消加锁操作、反之则取消\n if (failed)\n cancelAcquire(node);\n }\n }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"公平锁,当前的线程会进入一个队列中最后一个,等待到他的上锁。如果当前的线程表示获取到锁,且也是队列的第一个位置。会将自己变成锁的独占线程,只有自己才持有这个锁的对象。同时这里进行了 CAS 的原子交换,设置状态为1。其中 0 为 未上锁状态,1为上锁状态。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"非公平锁"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"/**\n * Sync object for non-fair locks\n */\n static final class NonfairSync extends Sync {\n private static final long serialVersionUID = 7316153563782823691L;\n\n /**\n * Performs lock. Try immediate barge, backing up to normal\n * acquire on failure.\n */\n final void lock() {\n // 先进行抢占锁,如果如可以修改状态,则直接变成上锁状态\n if (compareAndSetState(0, 1))\n // 设置独占线程\n setExclusiveOwnerThread(Thread.currentThread());\n else\n // 加锁\n acquire(1);\n }\n\n protected final boolean tryAcquire(int acquires) {\n return nonfairTryAcquire(acquires);\n }\n }\n\n /**\n * Performs non-fair tryLock. tryAcquire is implemented in\n * subclasses, but both need nonfair try for trylock method.\n */\n final boolean nonfairTryAcquire(int acquires) {\n // 这个和公平锁里面差不多\n final Thread current = Thread.currentThread();\n int c = getState();\n if (c == 0) {\n if (compareAndSetState(0, acquires)) {\n setExclusiveOwnerThread(current);\n return true;\n }\n }\n else if (current == getExclusiveOwnerThread()) {\n int nextc = c + acquires;\n if (nextc < 0) // overflow\n throw new Error(\"Maximum lock count exceeded\");\n setState(nextc);\n return true;\n }\n return false;\n }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"非公平锁,先进行抢占锁,先查看线程是否释放了锁,如果释放了,当前线程则直接上锁,这样的好处就是减少了线程之间的等待,加快了上锁的机制,避免了排队时竞争所导致的延时,提高了性能,如果没有释放锁,则进入到队列的最后一个等待上锁。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"小结一下。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d9/d916c495b072428a5c2c18019f654e32.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"释放锁机制。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"\t\t/**\n * Attempts to release this lock.\n *\n *

If the current thread is the holder of this lock then the hold\n * count is decremented. If the hold count is now zero then the lock\n * is released. If the current thread is not the holder of this\n * lock then {@link IllegalMonitorStateException} is thrown.\n *\n * @throws IllegalMonitorStateException if the current thread does not\n * hold this lock\n */\n public void unlock() {\n // 携带 1\n sync.release(1);\n }\n\n\n public final boolean release(int arg) {\n // 释放成功则为 true 否则是 false\n if (tryRelease(arg)) {\n Node h = head;\n if (h != null && h.waitStatus != 0)\n // 唤醒队列后面的线程\n unparkSuccessor(h);\n // 释放成功\n return true;\n }\n // 释放失败\n return false;\n }\n\n\n\n protected final boolean tryRelease(int releases) {\n\n // c = 0\n int c = getState() - releases;\n // 如果不是当前线程和不是独占线程\n if (Thread.currentThread() != getExclusiveOwnerThread())\n // 直接抛出错\n throw new IllegalMonitorStateException();\n boolean free = false;\n if (c == 0) {\n // 释放锁\n free = true;\n // 独占线程设置null\n setExclusiveOwnerThread(null);\n }\n // 0\n setState(c);\n return free;\n }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"锁的释放,比较简单。将锁状态重新设置回 0,同时独占线程也设置null,之后唤醒后面的队列里面的线程,完成释放。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"源码总结"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"ReentrantLock"},{"type":"text","text":" 创建的时候,默认是非公平锁,不过你也可以在构造的时候,也可以创建一个公平锁。 其中通过 "},{"type":"text","marks":[{"type":"strong"}],"text":"CAS"},{"type":"text","text":" 改变 "},{"type":"text","marks":[{"type":"strong"}],"text":"state"},{"type":"text","text":" 的状态来改变锁的数值, 0 表示有锁可以获取,1 表示锁已被获取,来设置锁的独占线程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在公平锁的机制中,请求锁的线程会直接排到一个队列中(通过一个双向链表来模拟的队列)的最后一个,去获取锁。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"非公平锁的机制中,请求锁的线程首先会先通过 "},{"type":"text","marks":[{"type":"strong"}],"text":"CAS"},{"type":"text","text":" 来改变 "},{"type":"text","marks":[{"type":"strong"}],"text":"state"},{"type":"text","text":" 的锁状态,如果可以改变(0 -> 1),则直接获取到锁,将自身设置成独占锁。这样的好处就减少了一些进队列、加载队列、唤醒线程等性能消耗。如果未能修改到 "},{"type":"text","marks":[{"type":"strong"}],"text":"state"},{"type":"text","text":" 的状态,也会变成公平锁的机制,进入到队列的最后一个,等待到它去获取锁。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"锁的释放,将 "},{"type":"text","marks":[{"type":"strong"}],"text":"state"},{"type":"text","text":" 重新设置回 0,同时独占线程(你也可以认为这是持有锁的线程对象)设置null,之后唤醒排在它下个的线程。这一系列步骤做完,则宣告锁的释放。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"优缺点 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"非公平锁"},{"type":"text","text":",确实性能比较高。不过也有一个显而易见的缺点,我们可以想象一下,当你在排队吃饭的时候,轮到你吃饭的时候,这时候突然来一个人插在你前面,提前打饭了,导致你打饭时间变长了,如果这时候在有几个人在也突然插到你前打饭,又会继续导致你打饭时间变得更长。那如果放到线程里面,突然其他线程提前获取到了锁,那会导致当前线程获取到锁时间变长,而导致线程阻塞,迟迟未获取到锁。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以得根据业务去选择合适的锁类型,进行上锁,尽可能的避免有一些重要的业务因为上锁而阻塞到。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"声明"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者: Sinsy 本文链接:https://blog.sincehub.cn/2020/11/10/jdk-reentrantLock/ "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"版权声明:本文为博主原创文章,遵循 "},{"type":"link","attrs":{"href":"https://creativecommons.org/licenses/by-sa/4.0/deed.zh","title":null},"content":[{"type":"text","text":"CC 4.0 BY-SA"}]},{"type":"text","text":" 版权协议,转载请附上原文声明。 如您有任何商业合作或者授权方面的协商,请给我留言:[email protected]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"引用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[1] "},{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html","title":null},"content":[{"type":"text","text":"Lock (Java Platform SE 8 )"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章