Reentrantlock of JDK source code series

InfoQ 2020-11-10 19:05:56
reentrantlock jdk source code series


{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Recently will "},{"type":"text","marks":[{"type":"strong"}],"text":"ReentrantLock"},{"type":"text","text":" I learned it once and read the source code again , Record the learning process "}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"JDK Source series "}]},{"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 Source code series 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 Source code series HashMap"}]}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":" Use "}]},{"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":" Using the lock mechanism , To ensure thread safety "}]},{"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 // Resource blocks protected by this lock \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":" Or you can use tryLock() Method , In multithreading , When a thread releases a lock , Just try to get the lock ."}]},{"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 // Resource blocks protected by this lock \n } finally {\n lock.unlock();\n }\n } else {\n // Other operations , Not protected by a lock \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":" This method , Unlock until you make sure you get the lock , And it doesn't try to unlock when it's not locked ."}]},{"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":" If you try to get a lock, it's too long , You can also add time to the process of acquiring a lock , Timeout will directly interrupt the thread ."}]},{"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":" If you want the module of the current lock not to execute immediately , You can also call await Mechanism "}]},{"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":" occasionally , When you encounter a long business process , It's been too long to hold , Consider the mechanism of breaking the lock , Release the lock ."}]},{"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":" Application scenario comparison "}]},{"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":" Source code "}]},{"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":" First look at the class "}]},{"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":" Inherit upward "},{"type":"text","marks":[{"type":"strong"}],"text":"Lock"},{"type":"text","text":" Interface , as well as "},{"type":"text","marks":[{"type":"strong"}],"text":"Serializable"},{"type":"text","text":", It's all implemented "},{"type":"text","marks":[{"type":"strong"}],"text":"Lock"},{"type":"text","text":" Methods ."}]},{"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() Get the lock "}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"void lockInterruptibly() Interrupt locking mechanism "}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"boolean tryLock() Other threads have release locks , To get the lock "}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"boolean tryLock(long time, TimeUnit unit) Thread is idle time for a given time , And other threads have release locks , To get the lock "}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"void unlock() Release the lock "}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Condition newCondition() Give the lock binding condition "}]}]}]},{"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":" Instantiate lock "}]},{"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":" here , There are two structures , One is a nonparametric construction , One is to pass in a Boolean value ."}]},{"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 // Create an unfair lock \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 Fair lock false Not fair lock \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":" By default, we construct an unfair lock , You can also directly set what type of lock to create , Like fair lock 、 Not fair lock ."}]},{"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":" Let's look at the fair lock first ."}]},{"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 // When using lock.lock() When it comes to At the same time the incoming 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 // here acquires = 1 refer to Locked state 0 It's not locked \n protected final boolean tryAcquire(int acquires) {\n // Get the current thread object \n final Thread current = Thread.currentThread();\n // Whether it is locked or not , The first default is 0\n int c = getState();\n if (c == 0) {\n // hasQueuedPredecessors Is it the current thread , The data structure of the two-way linked list is used , Make one queue, This means that the thread can be locked at this time . There's no need to line up \n if (!hasQueuedPredecessors() &&\n // CAS After comparison, the modification is successful \n compareAndSetState(0, acquires)) {\n // Set the current thread to exclusive thread \n setExclusiveOwnerThread(current);\n // Lock acquired successfully \n return true;\n }\n }\n // Exclusive thread \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 // The state of the synchronization lock = 1\n setState(nextc);\n return true;\n }\n // Other threads did not get lock \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 // Try to lock \n if (!tryAcquire(arg) &&\n // First add the current thread of the thread to the queue, the last one , And then I was deciding if he was locked \n acquireQueued(addWaiter(Node.EXCLUSIVE), arg))\n // If not, interrupt the thread directly \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 // Threads in the queue holding the lock \n final boolean acquireQueued(final Node node, int arg) {\n boolean failed = true;\n try {\n boolean interrupted = false;\n // It's a dead loop where you determine who is currently getting the lock \n for (;;) {\n // Point to next node \n final Node p = node.predecessor();\n // The first one in the queue , And get the lock , Turn the current thread into an exclusive thread \n if (p == head && tryAcquire(arg)) {\n setHead(node);\n p.next = null; // help GC\n failed = false;\n // If you get the lock , You do not need to interrupt the current thread and return a false\n return interrupted;\n }\n // The thread is blocked \n if (shouldParkAfterFailedAcquire(p, node) &&\n parkAndCheckInterrupt())\n // Interrupt the mechanism of lock acquisition \n interrupted = true;\n }\n } finally {\n // If you get the lock Then, no lock operation is needed 、 If not, cancel \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":" Fair lock , The current thread goes to the last one in a queue , Waiting for him to lock . If the current thread indicates that the lock is obtained , And it's also the first location for the queue . Will turn itself into an exclusive thread of a lock , Only one holds the object of this lock . At the same time CAS The exchange of atoms , Set state to 1. among 0 by It's not locked ,1 It's locked ."}]},{"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":" Not fair lock "}]},{"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 // First line preemptive lock , If you can modify the status , It will be locked directly \n if (compareAndSetState(0, 1))\n // Set exclusive thread \n setExclusiveOwnerThread(Thread.currentThread());\n else\n // Lock \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 // This is almost the same as the fair lock \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":" Not fair lock , First line preemptive lock , First, check if the thread has released the lock , If you release , The current thread is locked directly , The advantage is to reduce the waiting between threads , Speed up the locking mechanism , The delay caused by competition is avoided , Improved performance , If the lock is not released , Then enter the last queue to wait for the lock ."}]},{"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":" To sum up ."}]},{"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":" Release lock mechanism ."}]},{"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 // carry 1\n sync.release(1);\n }\n\n\n public final boolean release(int arg) {\n // Successful release means true It is false\n if (tryRelease(arg)) {\n Node h = head;\n if (h != null && h.waitStatus != 0)\n // Wake up the thread behind the queue \n unparkSuccessor(h);\n // Release successful \n return true;\n }\n // Release failed \n return false;\n }\n\n\n\n protected final boolean tryRelease(int releases) {\n\n // c = 0\n int c = getState() - releases;\n // If it is not the current thread and not the exclusive thread \n if (Thread.currentThread() != getExclusiveOwnerThread())\n // Throw it wrong \n throw new IllegalMonitorStateException();\n boolean free = false;\n if (c == 0) {\n // Release the lock \n free = true;\n // Exclusive thread settings 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":" The release of the lock , Relatively simple . Reset the lock state back to 0, At the same time, the exclusive thread is also set null, Then wake up the threads in the queue , Complete release ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":" Source code summary "}]},{"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":" At the time of creation , Default is unfair lock , But you can also be in the construction time , You can also create a fair lock . Among them through "},{"type":"text","marks":[{"type":"strong"}],"text":"CAS"},{"type":"text","text":" change "},{"type":"text","marks":[{"type":"strong"}],"text":"state"},{"type":"text","text":" State to change the lock value , 0 Indicates that there is a lock that can be obtained ,1 Indicates that the lock has been acquired , To set the exclusive thread of the lock ."}]},{"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":" In the fair lock mechanism , The thread that requests the lock is queued directly into a queue ( A queue simulated by a bidirectional linked list ) The last , To get the lock ."}]},{"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":" In the mechanism of unfair lock , The thread requesting the lock will first pass through "},{"type":"text","marks":[{"type":"strong"}],"text":"CAS"},{"type":"text","text":" To change "},{"type":"text","marks":[{"type":"strong"}],"text":"state"},{"type":"text","text":" Lock state of , If you can change (0 -> 1), The lock is obtained directly , Set itself to an exclusive lock . This reduces the number of queues 、 Load queue 、 Wake up threads and other performance consumption . If it cannot be modified to "},{"type":"text","marks":[{"type":"strong"}],"text":"state"},{"type":"text","text":" The state of , It will also become a mechanism for fair lock , Enter the last of the queue , Wait for it to get the lock ."}]},{"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":" The release of the lock , take "},{"type":"text","marks":[{"type":"strong"}],"text":"state"},{"type":"text","text":" Reset back to 0, At the same time monopolize the thread ( You can also think of this as a thread object holding a lock ) Set up null, Wake up the thread that is next to it . This series of steps is done , The lock is released ."}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":" Advantages and disadvantages "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":" Not fair lock "},{"type":"text","text":", It's true that the performance is relatively high . But there is also an obvious disadvantage , We can imagine that , When you're in line for dinner , It's your turn to eat , At this moment, a man comes in front of you , I had a meal in advance , It has led to your rice growing , If at this time, a few people suddenly cut in front of you to make a meal , It will continue to cause you to cook longer . If you put it in the thread , Suddenly other threads get the lock in advance , That will cause the current thread to acquire the lock for a longer time , And cause the thread to block , It's too late to get the lock ."}]},{"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":" So we have to choose the appropriate lock type according to the business , To lock , Try to avoid blocking some important business due to lock ."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":" Statement "}]},{"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":" author : Sinsy Link to this article :https://blog.sincehub.cn/2020/11/10/jdk-reentrantLock/ "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" Copyright notice : This article is an original blog article , follow "},{"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":" Copyright agreement , Please attach the original statement for reprint . If you have any business cooperation or authorization negotiation , Please leave me a message :550569627@qq.com"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":" quote "}]},{"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}}]}

版权声明
本文为[InfoQ]所创,转载请带上原文链接,感谢

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云