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 introduces the summary of knowledge points of multithreading and high concurrency. In daily operation, I believe that many people have doubts about the summary of knowledge points of multithreading and high concurrency. The editor consulted all kinds of data and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the doubts of "multithreading and high concurrency knowledge point summary". Next, please follow the editor to study!
1. Four ways to create a thread
Implement the Runnable rewrite run method
Inherit Thread override run method
Thread pool creation Executors.newCachedThreadPool ()
Implement the Callable interface
2. Thread thread operation method
Current thread sleep specifies mills milliseconds
Thread.sleep ([mills])
The current thread gracefully relinquishes the right of execution
Thread.yield ()
For example, Thread T1, T2, calls t1.join () in the run method of T2, and the thread T2 will wait for T1 to complete and execute
Join
3. Thread State usage scenario after NEWThread is created, before start, RUNNABLE calls the start () method, which is the only way for the thread to enter the running state.
Specifically divided into ready and running, when a thread is suspended or calls Thread.yield () for readyWAITING, when one thread executes Object.wait (), it must be waiting for another thread to execute Object.notify () or Object.notifyAll ().
Or a thread thread, when thread.join () is executed in the main thread, the main thread waits for that thread to finish execution. When a thread executes LockSupport.park (), it is waiting for LockSupport.unpark (thread) to be executed. When the thread is in this wait, its state is WAITING. It is important to note that there is no time limit for waiting. When a thread with this state is found, if it is in this state for a long time, you also need to pay attention to whether there are any logic exceptions within the program.
TIMED_WAITING
The difference between this state and WAITING state is that there is a certain time limit for waiting in this state.
Thread.sleep (long)
Object.wait (long)
Thread.join (long)
LockSupport.parkNanos ()
LockSupport.parkUntil ()
The state of the BLOCKED after the end of execution of the TERMINATED thread when entering the method or block of code modified by the synchronized keyword (acquiring the lock).
Once a thread is terminated, it cannot be revived.
Calling the start () method on a terminated thread throws a java.lang.IllegalThreadStateException exception
4. Synchronized
The object is locked, not the code.
This is equivalent to the current class. class
Locking method, non-locking method simultaneously
Lock an exception during execution will automatically release the lock
The lock acquired by synchronized is reentrant
Lock upgrade bias lock-spin lock-weight lock
Synchronized (object) cannot use basic data types such as String constant / Integer,Long
When locking an object, make sure that the object cannot be overridden. It is best to add a final definition.
4. Volatile
Ensure thread visibility
Prohibit instruction reordering
Volatile cannot guarantee the consistency of multiple thread modifications, and the synchronized keyword is still needed to maintain consistency.
Volatile reference types (including arrays) can only guarantee the visibility of the reference itself, not the visibility of internal fields. Volatile key words can only be used for variables and cannot decorate methods and code blocks.
5. Efficiency comparison between synchronized, AtomicLong and LongAdder
Synchronized needs locking and is inefficient; AtomicLong does not need to apply for locks and uses CAS mechanism; LongAdder uses segmented locks, so it is efficient, and LongAdder is the most suitable when the number of concurrency is particularly high.
6. The piecewise locking principle of ConcurrentHashMap
Segmented locking is to lock the data into segments and further fine-grained the lock, which helps to improve the efficiency of concurrency. The reason why the HashTable container shows inefficiency in the highly competitive concurrent environment is that all threads accessing HashTable must compete for the same lock. If there are multiple locks in the container, each lock is used to lock part of the data in the container, then when multiple threads access the data of different data segments in the container, there will be no lock competition between threads, which can effectively improve the efficiency of concurrent access. This is the lock segmentation technology used by ConcurrentHashMap. First, the data is stored in segments, and then each piece of data is assigned a lock. When a thread occupies the lock to access one segment of data, the data of other segments can also be accessed by other threads.
7. ReentrantLock
ReentrantLock can replace synchronized, but ReentrantLock must manually open / close the lock. Synchronized automatically releases the lock when it encounters an exception. ReentrantLock needs to be closed manually. Generally, it is placed in finally to close the definition lock Lock lock = new ReentrantLock (); open lock.lock (); close lock.unlock (); use Reentrantlock to "try to lock" tryLock, so it cannot be locked or cannot be locked within a specified period of time, and the thread can decide whether to continue waiting. Use tryLock to try to lock, regardless of whether it is locked or not, the method will continue to execute. You can also specify the time of tryLock according to the return value of tryLock. Because tryLock (time) throws an exception, you must pay attention to the handling of unclock. You must put it in finally. If tryLock is not locked, you do not need unlock to use ReentrantLock to call the lockInterruptibly method. You can respond to the thread interrupt method while a thread is waiting for the lock. New ReentrantLock (true) can be interrupted to indicate a fair lock. Default is false without parameters, and unfair lock
8. CountDownLatch
The countDownLatch class allows one thread to wait for other threads to execute after each has finished executing. This is achieved through a counter whose initial value is the number of threads. When the countDown () method is called, every time a thread finishes execution, the value of the counter is-1. When the counter value is 0, all threads are finished, and then the thread waiting on the lock can resume work.
The countDown () method is called in the thread to start counting; in the thread that calls the await () method, execution continues after the counter is 0, otherwise it waits all the time; you can also use latch.await (timeout, unit) to continue if the counter is not 0 after waiting for timeout time. The code after countDown () is not different from join by counter control. Threads that use join will be blocked, threads that use countDown will not be affected, and will be blocked only when await is called.
8. CyclicBarrier
The effect is to make all threads wait for the specified number of threads (specified by the constructor) to complete before moving on to the next step. Constructor: public CyclicBarrier (int parties)
Public CyclicBarrier (int parties) public CyclicBarrier (int parties, Runnable barrierAction)
Parties is the number of threads; barrierAction is the last task to arrive at the thread
All threads wait for all threads to reach the fence before continuing, and the last thread to arrive completes the Runnable task.
Implementation principle: a Lock object is defined inside the CyclicBarrier. Every time a thread calls the await method, it subtracts the number of intercepted threads by 1, and then determines whether the remaining number of intercepts is the initial value parties. If not, enter the conditional queue of the Lock object and wait. If so, execute the Runnable method of the barrierAction object, and then put all threads in the lock's conditional queue into the lock waiting queue, which in turn acquires the lock and releases the lock.
9. Phaser
A reusable synchronization barrier that functions similar to CyclicBarrier and CountDownLatch, but supports more flexible use.
Phaser enables us to build obstacles such as logical threads that need to perform the next step, etc.
We can coordinate multiple execution phases and reuse Phaser instances for each program phase. Each stage can have a different number of threads waiting to move on to another stage. We will look at an example of the usage phase later.
To participate in the coordination, the thread needs to use the Phaser instance register () itself. Please note: this only increases the number of registrants, and we cannot check whether the current thread is registered-we must subclass the implementation to support this operation.
The thread prevents it from reaching the barrier by calling arriAndAwaitAdvance (), which is a blocking method. When the number reaches the number equal to the number of registrations, the execution of the program will continue and the number will increase. We can get the current quantity by calling the getPhase () method.
10. ReadWriteLock
The concrete implementation of ReadWriteLock is ReentrantReadWriteLock.
ReadWriteLock allows you to create read and write locks, respectively.
ReadWriteLock readWriteLock = new ReentrantReadWriteLock (); Lock readLock = readWriteLock.readLock (); Lock writeLock = readWriteLock.writeLock ()
When using ReadWriteLock, the condition is that the same data is read by a large number of threads, but only a few threads modify it. ReadWriteLock guarantees that:
Only one thread is allowed to write (other threads can neither write nor read)
When there is no write, multiple threads are allowed to read at the same time (improve performance)
Read-write separation locks can effectively help reduce lock competition and improve system performance. Read-write locks are not mutually exclusive, read-write, write-read are mutually exclusive.
11. Semaphore
Semaphore is a count semaphore and must be released by the thread that acquired it. It is often used to limit the number of threads that can access certain resources, such as stream restriction through Semaphore.
For Semaphore, what it wants to ensure is the mutual exclusion of resources rather than the synchronization of resources, which can not be guaranteed at the same time, but it can guarantee the mutual exclusion of resources. It only limits the number of threads that access certain resources, but does not achieve synchronization.
Common methods:
1. Acquire (int permits)
Obtaining a given number of permissions from this semaphore blocks the thread until these permissions are provided, or the thread has been interrupted. It's like a student occupying two windows. This also corresponds to the corresponding release method.
2. Release (int permits)
Releases a given number of licenses and returns them to the semaphore. This corresponds to the above method, how much does a student have to release after occupying several windows?
3. AvailablePermits ()
Returns the number of licenses currently available in this semaphore. That is, to return how many windows are currently available.
4. ReducePermits (int reduction)
Reduces the number of available licenses by the specified amount of reduction.
5. HasQueuedThreads ()
Query whether there is a thread waiting to get the resource.
6. GetQueueLength ()
Returns the estimated number of threads waiting to be acquired. This value is only an estimated number.
7. TryAcquire (int permits, long timeout, TimeUnit unit)
If all licenses are available for this semaphore within a given wait time, and the current thread is not interrupted, the given number of licenses are obtained from this semaphore.
8. AcquireUninterruptibly (int permits)
Obtain a given number of permissions from this semaphore and block the thread until these permissions are provided.
12. Exchanger
The encapsulation tool class used to exchange data between two working threads means that if one thread wants to exchange data with another thread after completing a certain transaction, the first thread that takes out the data first will wait for the second thread. The corresponding data can not be exchanged with each other until the second thread arrives with the data. It is defined as an Exchanger generic type, where V represents the exchangeable data type. The external interface is very simple, as shown below:
Exchanger (): no-parameter construction method.
V exchange (V v): wait for another thread to reach this exchange point (unless the current thread is interrupted), then pass the given object to that thread and receive the thread's object.
V exchange (V v, long timeout, TimeUnit unit): wait for another thread to reach this exchange point (unless the current thread is interrupted or exceeds the specified wait time), and then pass the given object to the thread and receive the thread's object.
13. LockSupport
LockSupport is a very convenient and practical thread blocking tool that can block threads anywhere.
LockSupport's static method park () blocks the current thread, similar to parkNanos (), parkUntil (), and so on, which implement a time-limited wait.
Method description void park (): blocking the current thread, if the unpark method is called or the current thread is interrupted, the function of returning void park (Object blocker) from the park () method is the same as method 1, and the input parameter adds an Object object to record the blocking object that causes the thread blocking to facilitate problem troubleshooting; void parkNanos (long nanos) blocks the current thread with a maximum length of no more than nanos nanoseconds, adding the feature of timeout return The function of void parkNanos (Object blocker, long nanos) is the same as that of method 3. The input parameter adds an Object object to record the blocking object that causes thread blocking to facilitate problem troubleshooting. Void parkUntil (long deadline) blocks the current thread until the function of deadline;void parkUntil (Object blocker, long deadline) is the same as method 5. The input parameter adds an Object object to record the blocking object that causes thread blocking, which is convenient for problem troubleshooting.
Similarly, there are blocking methods, of course there are wake-up methods, what? unpark (Thread) method. This method wakes up the specified thread.
It is important to note that the execution order of the park method and the unpark method is not so strict. For example, the suspend and resume methods we mentioned in the Thread class will never wake up if they are in the wrong order, but the park and unpark methods will not, because LockSupport uses a semaphore-like mechanism. He prepares a license for each thread (not available by default), and if it is possible, the park function returns immediately, and consumes the license (that is, making the license unavailable), and if it is not available, it will block. The unpark method makes a license available.
14. AQS
AQS is the abbreviation of AbstractQueuedSynchronizer
AQS is a synchronization framework provided under JDK for implementing blocking locks and related synchronizers based on FIFO waiting queues. This abstract class is designed as the base class for some synchronizers that can represent states with atomic int values. AQS manages a single integer about state information that can represent any state. For example, Semaphore uses it to represent the remaining number of permissions, ReentrantLock uses it to show how many locks have been requested by the thread that owns it, and FutureTask uses it to represent the status of the task (not yet started, run, completed, and cancelled)
Instructions for use:
UsageTo use this class as the basis of a synchronizer, redefine the following methods, as applicable, by inspecting and/or modifying the synchronization state using {@ link # getState, {@ link # setState} and/or {@ link # compareAndSetState}: {@ link # tryAcquire} {@ link # tryRelease} {@ link # tryAcquireShared} {@ link # tryReleaseShared} > {@ link # isHeldExclusively}
All of the above methods do not need to be implemented, and different methods can be selected according to the types of locks acquired: synchronizers that support exclusive (exclusive) lock acquisition should implement tryAcquire, tryRelease, and isHeldExclusively; synchronizers that support shared lock acquisition should implement tryAcquireShared, tryReleaseShared, and isHeldExclusively.
Brief Analysis of AQS
The main implementation of AQS is to maintain a "volatile int state" (representing shared resources) and a FIFO thread waiting queue (which is entered when multi-thread contention resources are blocked). Each node in the queue is an encapsulation of the thread, including the basic information of the thread, the status, the type of resource waiting, and so on.
There are three ways to access state:
GetState () setState () compareAndSetState ()
AQS 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) different custom synchronizers compete for shared resources in different ways. When implementing the custom synchronizer, you only need to implement the acquisition and release of the shared resource state. As for the maintenance of the specific thread waiting queue (such as getting resources failed to join the queue / wake up the queue, etc.), AQS has been implemented at the top level. The following methods are mainly implemented when implementing a custom synchronizer:
IsHeldExclusively (): whether the thread is monopolizing resources. You need to implement it only if you use condition.
TryAcquire (int): exclusive mode. If you try to get the resource, you will return true if you succeed and false if you fail.
TryRelease (int): exclusive mode. If you try to release the resource, return true if you succeed, or false if you fail. TryAcquireShared (int): sharing method. Try to get the resource. A negative number indicates failure; 0 indicates success, but there are no remaining resources available; a positive number indicates success and there are remaining resources.
TryReleaseShared (int): sharing method. Try to release the resource, if you are allowed to wake up the subsequent waiting node to return true, otherwise return false.
Take ReentrantLock as an example
State is initialized to 0, indicating that the state is not locked.
When thread A lock (), tryAcquire () is called to monopolize the lock and state+1.
After that, other threads fail when they tryAcquire (), and the other threads don't have a chance to acquire the lock until the A thread unlock () to state=0 (that is, release the lock).
Of course, thread A can acquire the lock repeatedly (state accumulates) before releasing the lock, which is the concept of reentrant.
Note, however, that you release as many times as you get, so that state can return to zero.
Take CountDownLatch as an example
The task is divided into N sub-threads to execute, and the state is initialized to N (note that N is the same as the number of threads).
These N child threads are executed in parallel, and after each child thread completes execution, countDown () once, state will CAS minus 1.
When all the child threads have finished executing (that is, state=0), the main calling thread unpark (), and then the main calling thread returns from the await () function to continue the rest of the action.
In general, custom synchronizers are either exclusive or shared
They only need to implement one of tryAcquire-tryRelease and tryAcquireShared-tryReleaseShared.
However, AQS also supports both exclusive and shared ways for custom synchronizers, such as "ReentrantReadWriteLock".
15. Basic concept of lock
Fair lock / unfair lock
Reentrant lock
Exclusive lock / shared lock
Mutex / read-write lock
Optimistic lock / pessimistic lock
Sectional lock
Bias lock / lightweight lock / heavyweight lock
Spin lock
Fair lock / unfair lock
Fair lock means that multiple threads acquire the lock in the order in which the lock is applied for.
Unfair lock means that multiple threads do not acquire locks in the order in which they apply for locks, and it is possible that the thread that applies later takes priority over the thread that applies first; it may cause priority reversal or hunger.
For Java ReentrantLock, the constructor specifies whether the lock is a fair lock, and the default is an unfair lock.
The advantage of unfair locks is that the throughput is larger than fair locks.
For Synchronized, it is also an unfair lock. Unlike ReentrantLock, which implements thread scheduling through AQS, there is no way to make it a fair lock.
Reentrant lock
A reentrant lock, also known as a recursive lock, means that when the same thread acquires the lock in the outer method, the inner method automatically acquires the lock.
Both ReentrantLock and Synchronized are reentrant locks.
One of the advantages of reentrant locks is that deadlocks can be avoided to some extent.
Exclusive lock / shared lock
An exclusive lock means that the lock can only be held by one thread at a time.
A shared lock means that the lock can be held by multiple threads.
For ReentrantLock, it is an exclusive lock.
But for another implementation class of Lock, ReadWriteLock, its read lock is a shared lock and its write lock is exclusive. The shared lock of the read lock ensures that concurrent reads are very efficient, and the processes of reading and writing are mutually exclusive. Exclusive lock and shared lock are also realized through AQS, through the implementation of different methods to achieve exclusive or shared.
For Synchronized, it is, of course, an exclusive lock.
Mutex / read-write lock
The exclusive lock / shared lock mentioned above is a broad term, and the mutex / read-write lock is the concrete implementation.
The concrete implementation of mutex in Java is ReentrantLock.
The concrete implementation of read-write lock in Java is ReadWriteLock.
Optimistic lock / pessimistic lock
Optimistic and pessimistic locks do not refer to specific types of locks, but to the perspective of concurrent synchronization.
Pessimistic lock (Synchronized and ReentrantLock)
It is considered that the concurrent operation of the same data must be modified, even if there is no modification, it will be considered modified.
Therefore, for the concurrent operation of the same data, the pessimistic lock takes the form of locking. Pessimistically, unlocked concurrency operations are bound to go wrong.
Optimistic lock (java.util.concurrent.atomic package)
It is considered that the concurrent operation of the same data will not be modified. When you update the data, you will try to update the data and update the data again and again. Optimistically, there is nothing wrong with unlocked concurrent operations.
Pessimistic locks are suitable for scenarios with a large number of write operations, while optimistic locks are suitable for scenarios with a lot of read operations.
Unlocking brings a lot of performance improvements.
The use of pessimistic locks in Java is the use of various locks.
The use of optimistic locking in Java is lock-free programming, often using the CAS algorithm. A typical example is the atomic class, which updates atomic operations through CAS spin.
Sectional lock
Segmented lock is actually a kind of lock design, not a specific kind of lock. The realization of ConcurrentHashMap concurrency is to achieve efficient concurrent operation in the form of segmented lock.
The segmented lock in ConcurrentHashMap is called Segment, which is similar to the structure of HashMap (the implementation of HashMap in JDK7 and JDK8), that is, there is an internal Entry array, each element in the array is a linked list, and it is also a ReentrantLock (Segment inherits ReentrantLock). When the put element is needed, instead of locking the entire hashmap, we first know which segment it is going to put through hashcode, and then lock the segment, so when multithreaded put, as long as it is not placed in a segment, real parallel insertion is achieved. However, when you count size, you need to get all the segmented locks when you get the global information of hashmap.
The purpose of the segmented lock is to refine the granularity of the lock, and when the operation does not need to update the entire array, the locking operation is performed on only one item in the array.
Bias lock / lightweight lock / heavyweight lock
These three locks refer to the state of the lock and are specific to Synchronized. Efficient Synchronized is realized by introducing lock upgrade mechanism in Java 5. The status of these three locks is indicated by the fields of the object monitor in the object header.
Bias lock
Means that a piece of synchronization code is accessed by a thread all the time, then the thread automatically acquires the lock. Reduce the cost of acquiring locks.
Lightweight lock
It means that when the lock is biased and accessed by another thread, the biased lock will be upgraded to a lightweight lock, and other threads will try to acquire the lock in the form of spin without blocking and improving performance.
Weight lock
It means that when the lock is a lightweight lock, although the other thread is spinning, the spin will not last forever. When the lock is not acquired for a certain number of spins, it will enter the block, and the lock will expand to a heavy lock. Heavyweight locks can cause other requesting threads to enter blocking and slow performance.
Spin lock
In Java, spin lock means that the thread trying to acquire the lock does not block immediately, but uses a loop to try to acquire the lock, which has the advantage of reducing the consumption of thread context switching, while the disadvantage is that the loop consumes CPU. For a typical example of a spin lock implementation, you can refer to the spin lock implementation.
At this point, the study of "multi-threading and high concurrency knowledge summary" is over. I hope to be able to solve everyone's doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
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.