In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly explains "how to understand the synchronizer design of Java concurrency". The content of the explanation is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "how to understand the synchronizer design of Java concurrency".
Foreword:
There is a race condition when Java concurrent memory model details learn that multiple processes (threads) read shared resources.
In the computer, a synchronizer is designed to coordinate the execution order between processes (threads). The synchronizer functions like boarding security personnel to coordinate passengers through in order.
In Java, a synchronizer can be understood as an object that coordinates the execution order of threads according to its own state. Such as locks (Lock), semaphores (Semaphore), barriers (CyclicBarrier), blocking queues (Blocking Queue).
These synchronizers are different in functional design, but have something in common in the internal implementation.
1. Synchronizer
The design of synchronizer generally includes several aspects: state variable design (internal state of synchronizer), access condition setting, state update, waiting mode, notification strategy.
An access condition is a condition that controls whether a thread can execute (accessing a shared object), and it is often closely related to state variables. The notification policy is a way for a thread to notify other waiting threads after releasing the locked state. There are generally the following situations:
Notify all waiting threads.
Notify 1 random N waiting threads.
Notify 1 specific N waiting threads
Take a look at the following example, through the lock synchronizer
Public class Lock {/ / status variable isLocked private boolean isLocked=false; public synchronized void lock () throws InterruptedException {/ / access conditions otherwise wait for while (isLocked) {/ / blocking waiting for wait ();} / / status update thread gets access isLocked= true } public synchronized void unlock () {/ / status update thread releases access rights isLocked = false; / / Notification Policy object.notify | object.notifyAll notify ();}}
We use counting semaphores to control the number of simultaneous operations. A connection pool is simulated here.
Public class PoolSemaphore {/ / status variable actives counter private int actives = 0; private int max; public PoolSemaphore (int max) {this.max = max;} public synchronized void acquire () throws InterruptedException {/ / access condition activation is less than the maximum limit, otherwise wait for while (this.actives = = max) wait () / / status update thread gets access this.actives++; / / notifies policy object.notify | object.notifyAll this.notify ();} public synchronized void release () throws InterruptedException {/ / access condition activation is not 0, otherwise wait for while (this.actives = = 0) wait () / / status update thread gets access rights this.actives--; / / Notification Policy object.notify | object.notifyAll this.notify ();}} 1.1 Atomic instruction
In the synchronizer design, the most important operation logic is "if the condition is met, update the state variable to mark the thread to obtain or release access", this operation should be atomic.
For example, the atomic instruction of the test-and-set computer means to set a new value if the condition is satisfied.
Function Lock (boolean * lock) {while (test_and_set (lock) = = 1);}
There are also many atomic instructions fetch-and-add compare-and-swap. Note that these instructions need hardware support to be valid.
In synchronous operation, the lock can be avoided and the efficiency can be improved by using computer atomic instructions. There is no support for test-and-set in java, but java.util.concurrent.atomic provides us with a lot of atomic API, which supports getAndSet and compareAndSet operations.
Take a look at the following example, the main difference is that the wait mode is different, above is blocking wait through wait (), and below is a non-blocking loop.
Public class Lock {/ / status variable isLocked private AtomicBoolean isLocked = new AtomicBoolean (false); public void lock () throws InterruptedException {/ / wait mode changes to spin wait while (! isLocked.compareAndSet (false, true)); / / status update thread gains access isLocked.set (true);} public synchronized void unlock () {/ / status update thread releases access isLocked.set (false) }} 1.2 instructions about blocking extensions
Blocking means that the process or thread state needs to be rolled over in order to resume execution after the restore. This operation is expensive and onerous, while threads are relatively lightweight based on the process. Thread blocking is implemented differently in different programming platforms, for example, Java runs based on JVM, so it is implemented by JVM.
In Java Concurrency in Practice, the author mentions
Competitive synchronization may require OS activities, which increases costs. When a lock is contended, the thread that did not acquire the lock must block. JVM can achieve blocking by rotating and waiting (repeatedly trying to acquire the lock until it succeeds) or by suspending blocked threads by the operating system. Which is more efficient depends on the relationship between the context switching overhead and the time before the lock is available. For short waits, it is best to use spin waiting; for long waits, it is best to use pauses. Some JVM adaptively choose between the two based on analysis data of past wait times, but most JVM simply suspend threads waiting for locks.
From the above, we can see that there are two ways for JVM to implement blocking
Rotation wait (spin-waiting) is simply understood as not pausing execution, but waiting in a circular way, which is suitable for short-term scenarios.
Suspend threads through the operating system.
Rotation waiting is enabled in JVM with-XX: + UseSpinning, and-XX: PreBlockSpi = 10 specifies the maximum number of rotations.
2 、 AQS
AQS is the abbreviation of AbstractQueuedSynchronizer. This section only makes a brief description of AQS, not comprehensive.
The ReentrantLock,CountDownLatch,Semaphore,CyclicBarrier and so on in the java.util.concurrent package are all based on the AQS synchronizer implementation.
The state variable is represented by int state, and the status is obtained and updated through the following API operation.
Int getState () void setState (int newState) boolean compareAndSetState (int expect, int update)
This state value has different meanings in different API. For example, ReentrantLock indicates the number of times the thread holding the lock acquires the lock, and Semaphore represents the number of remaining permissions.
On the Design of waiting Mode and Notification Strategy
AQS manages synchronization by maintaining a FIFO synchronization queue (Sync queue). It is blocked to join the queue when multithreads compete for shared resources. Thread blocking and awakening are achieved through LockSupport.park/unpark API.
It defines two ways to share resources.
Exclusive (exclusive, only one thread can execute, such as ReentrantLock)
Share (shared, multiple threads can execute at the same time, such as Semaphore/CountDownLatch)
Each node contains waitStatus (node status), prev (predecessor), next (successor), thread (queuing thread), nextWaiter (successor node of condition queue)
WaitStatus has the following values:
CANCELLED (1) indicates that the thread has been cancelled. When a timeout or interruption occurs, the node state is canceled, and then the state is no longer changed.
SIGNAL (- 1) indicates that the successor node is waiting for the previous wake-up. When the successor node joins the queue, the successor status is updated to SIGNAL.
CONDITION (- 2) indicates that the thread is waiting in the Condition queue. When another thread calls the Condition.signal () method, the node in the CONDITION state is transferred from Condition queue to Sync queue, waiting for the lock to be acquired.
PROPAGATE (- 3) in shared mode, after the current node is released, ensure that the successor node is effectively notified.
(0) the default state of the node when it joins the queue.
Several key API of AQS
In tryAcquire (int) exclusive mode, try to get resources. True is returned successfully, otherwise false.
In tryRelease (int) exclusive mode, try to release resources and return true successfully, otherwise false.
In tryAcquireShared (int) sharing mode, try to get resources. Returns a negative number as a failure, zero and a positive number as success and represents the remaining resources.
In tryReleaseShared (int) sharing mode, try to release the resource. If you are allowed to wake up the subsequent waiting node to return true, otherwise false.
IsHeldExclusively () determines whether the thread is monopolizing the resource.
2.1 acquire (int arg) public final void acquire (int arg) {if (/ / attempts to get the resource directly and returns directly if successful! tryAcquire (arg) & / / Thread blocks in the synchronization queue waiting to get the resource. If the waiting process is interrupted, true is returned, otherwise false acquireQueued (/ / marks the thread as exclusive and joins the tail of the synchronization queue. AddWaiter (Node.EXCLUSIVE), arg)) selfInterrupt ();} 2.2 release (int arg) public final boolean release (int arg) {/ / attempt to release resource if (tryRelease (arg)) {Node h = head; if (h! = null & & h.waitStatus! = 0) / / Wake up the next thread (successor node) unparkSuccessor (h); return true } return false;} private void unparkSuccessor (Node node) {.... Node s = node.next; / / find successor node if (s = = null | | s.waitStatus > 0) {/ / No successor or node has cancelled s = null; / / find a valid waiting node for (Node t = tail; t! = null & & t! = node; t = t.prev) if (t.waitStatus)
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.