In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-22 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >
Share
Shulou(Shulou.com)06/01 Report--
Introduction:
I saw the use of Lock when I was learning the interview experience shared by others yesterday. I remember that I also encountered the difference and use between synchronized and Lock in the last interview. Therefore, I sorted out the differences and usage of the two, at the same time, a summary of some common problems in the use of synchronized, and finally, with reference to the source code and documentation, wrote a few simple Demo for the use of Lock. Please criticize and correct.
Technical points:
1. Threads and processes:
Distinguish a process from a thread before you start. A program needs at least one process, and a process needs at least one thread. The relationship is the general structure of the thread-> process-> program. Therefore, the thread is the smallest unit of the program execution flow, and the process is an independent unit for the system to allocate and schedule resources. All of what we discuss below is based on threads.
2. Several important methods of Thread:
Let's first take a look at several important methods of Thread. A, start () method, call the method to start execution of the thread; b, stop () method, call the method to force the end of the thread execution; c, join method, call the method to wait for the thread to finish. D, the sleep () method, which is called when the thread enters the wait. E, the run () method, which is called to execute the thread's run () method directly, but the thread also runs the run () method when the start () method is called. The difference is that one is scheduled by the thread to run the run () method, and the other is to directly call the run () method in the thread!
Seeing this, some people may ask, what about wait () and notify ()? Note that the wait () and notify () methods are actually Object methods, not Thread methods! At the same time, wait () and notify () are used together to indicate thread suspension and thread recovery, respectively.
There is also a common problem, incidentally: the difference between wait () and sleep (). Simply put, wait () releases the object lock while sleep () does not. There is a lot of information on these questions, so I won't repeat them.
3. Thread status:
Threads have a total of 5 states, which is easy to understand through the introduction of the second knowledge point above.
New state: create a new thread object without calling the start () method
Ready state: the thread enters the ready state after calling the start () method, but that doesn't mean that the thread becomes the current thread as soon as the start () method is called, and is ready until it becomes the current thread. It is worth mentioning that the thread will also enter the ready state when it resumes during sleep and suspension.
Running status: the thread is set to the current thread and starts executing the run () method. That is, the thread enters the running state.
Blocking state: the thread is paused, for example, the thread enters the blocking state after calling the sleep () method
Death status: thread execution ends
4. Lock type
Reentrant lock: all synchronization methods in the execution object do not have to acquire the lock again
Interruptible lock: interruptible while waiting for the lock to be acquired
Fair lock: it is acquired according to the waiting time of the thread waiting to acquire the lock, and those with long waiting time have priority to acquire the lock.
Read-write lock: the resource is divided into two parts when reading and writing, multi-thread can be read together when reading, and must be written synchronously when writing.
The difference between synchronized and Lock
1. I classify the difference between the two into a table for comparison:
Category synchronizedLock exists the keyword of hierarchical Java. On the jvm level, it is the release of a class lock 1 to release the synchronization code of the thread that acquires the lock. 2. If the thread execution is abnormal, jvm will make the thread release the lock in the finally. Otherwise, it is easy to cause thread deadlock acquisition assuming A thread acquires the lock and B thread waits. If thread An is blocked, thread B will wait all the time depending on the situation. Lock has multiple ways to acquire locks. As we will say below, roughly, you can try to acquire a lock, and the thread can not wait for the lock state all the time. It can not judge that the lock type can be reentered, non-interruptible, unfair, reentrant, fair (both can be), performance, a small amount of synchronization, a large number of synchronization.
Perhaps, seeing that little is known about LOCK here, then let's move on to the further study of LOCK.
Detailed introduction of Lock and Demo
The following is the source code of the Lock API. The result after pruning by the author:
Public interface Lock {/ * * Acquires the lock. * / void lock (); / * * Acquires the lock unless the current thread is * {@ linkplain Thread#interrupt interrupted}. * / void lockInterruptibly () throws InterruptedException; / * * Acquires the lock only if it is free at the time of invocation. * / boolean tryLock (); / * * Acquires the lock if it is free within the given waiting time and the * current thread has not been {@ linkplain Thread#interrupt interrupted}. * / boolean tryLock (long time, TimeUnit unit) throws InterruptedException; / * * Releases the lock. * / void unlock ();} 12345678910111213141516171819202122324252627282930 from the Lock interface we can see that there is a main method. The function of these methods can be seen from the comments: 12
Lock (): acquire the lock and wait if the lock is temporarily used
Unlock (): release the lock
TryLock (): note that the return type is boolean. If the lock is occupied when the lock is acquired, false is returned, otherwise true is returned.
TryLock (long time, TimeUnit unit): compared with tryLock (), it gives a time limit to guarantee the waiting time for parameters.
LockInterruptibly (): in the way the lock is acquired, if a thread waits during the lock acquisition phase, it can interrupt the thread and do something else first.
Through the above explanation, we can roughly explain the problems such as "lock type (lockInterruptibly ())" and "lock status (tryLock ())" in the previous section, as well as the "can" that I wrote in the process of obtaining the lock, that is, I can try to acquire the lock, and the thread can not wait all the time.
The following is an example of general use of Lock. Note that ReentrantLock is the implementation of the Lock interface. twelve
Lock ():
Package com.brickworkers;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class LockTest {private Lock lock = new ReentrantLock (); / / methods that need to participate in synchronization private void method (Thread thread) {lock.lock (); try {System.out.println ("thread name" + thread.getName () + "lock acquired") } catch (Exception e) {e.printStackTrace ();} finally {System.out.println ("thread name" + thread.getName () + "lock released"); lock.unlock ();}} public static void main (String [] args) {LockTest lockTest = new LockTest () / / Thread 1 Thread T1 = new Thread (new Runnable () {@ Override public void run () {lockTest.method (Thread.currentThread ());}}, "T1") Thread T2 = new Thread (new Runnable () {@ Override public void run () {lockTest.method (Thread.currentThread ())}, "T2"); t1.start (); t2.start () } / / execution: thread name T1 got lock / / thread name T1 released lock / / thread name T2 got lock / / thread name T2 released lock 12345678910111213141516171819202122232426272829303133343536383940414444647484950
TryLock ():
Package com.brickworkers;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class LockTest {private Lock lock = new ReentrantLock (); / / the method that needs to participate in synchronization private void method (Thread thread) {/ * lock.lock (); try {System.out.println ("thread name" + thread.getName () + "lock acquired") } catch (Exception e) {e.printStackTrace ();} finally {System.out.println ("thread name" + thread.getName () + "lock released"); lock.unlock () } * / if (lock.tryLock ()) {try {System.out.println ("thread name" + thread.getName () + "lock obtained");} catch (Exception e) {e.printStackTrace ();} finally {System.out.println ("thread name" + thread.getName () + "lock released") Lock.unlock ();}} else {System.out.println ("I am" + Thread.currentThread (). GetName () + "someone has the lock, I don't want it");}} public static void main (String [] args) {LockTest lockTest = new LockTest () / / Thread 1 Thread T1 = new Thread (new Runnable () {@ Override public void run () {lockTest.method (Thread.currentThread ());}}, "T1") Thread T2 = new Thread (new Runnable () {@ Override public void run () {lockTest.method (Thread.currentThread ())}, "T2"); t1.start (); t2.start () } / / execution result: thread name T2 acquired the lock / / I am T1 someone is occupying the lock, I don't want it / / thread name T2 released the lock 123456789101112131415161718192021223242627282930313334353638394041424454647484950515354555758596061626364
See here, I believe everyone will also use how to use Lock, about tryLock (long time, TimeUnit unit) and lockInterruptibly () will not repeat. The former mainly has a waiting time, which writes a waiting time in the test code, while the latter mainly waits for an interrupt and throws an interrupt exception, which is not common and can be studied deeply by oneself if you like to explore.
The previous reference to "fair lock" is more important. Here we can mention ReentrantLock's definition of balanced lock. There are two paragraphs in the source code: 12 / * Sync object for non-fair locks * / static final class NonfairSync extends Sync {private static final long serialVersionUID = 7316153563782823691L; / * Performs lock. Try immediate barge, backing up to normal * acquire on failure. * / final void lock () {if (compareAndSetState (0,1)) setExclusiveOwnerThread (Thread.currentThread ()); else acquire (1);} protected final boolean tryAcquire (int acquires) {return nonfairTryAcquire (acquires) }} / * * Sync object for fair locks * / static final class FairSync extends Sync {private static final long serialVersionUID =-3000897897090466540L; final void lock () {acquire (1);} / * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. * / 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 }} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
From the above source code, you can control whether the lock is fair or not in Lock. Moreover, the default is unfair lock. The following is the constructor of ReentrantLock:
Public ReentrantLock () {sync = new NonfairSync (); / / default unfair lock} 123 records: the author is average, but the purpose of this blog in the introduction has been achieved. This is only a summary and summary of the author in the process of learning. If there are incorrect ones, you are welcome to criticize and point out. twelve
Extended learning: for the underlying implementation of LOCK, you can refer to:
Click the bottom layer of Lock to introduce the blog
For performance testing of the two synchronization methods, you can refer to:
Click to view two synchronized performance test blogs
Bloggers added in March 18:
Come back and read your blog. Found that the description of things is not complete. Here is a supplement, because the visit of this blog is large, so in order not to mislead you, try to introduce you to the correct expression:
1. The underlying implementation of the two locks:
Synchronized: we know that java uses bytecode instructions to control programs (not including hot code compiled into machine code here). In the byte instruction, there is a code block contained in the synchronized, then the execution of the 2-stage process will be formed.
Click to view the source code SyncDemo.class of SyncDemo.java, and you can see the following:
This is the bytecode instruction of this code snippet, which is not as difficult as you think. To get back to the point, we can clearly see that the mapping of synchronized to bytecode instructions is to add two instructions: monitorenter and monitorexit. When a thread encounters a monitorenter instruction, it tries to acquire the lock, and if it gets the lock, the lock count is + 1 (why add one, because it is a reentrant lock, so you need to use this lock count to determine the lock), and if you don't get the lock, then block. When it encounters monitorexit, it locks the counter-1. When the counter is 0, the lock is released.
So some friends are confused when they see this. There are two monitorexit on the picture. Answer this question immediately: as stated in my previous article, there are two mechanisms for synchronized lock release, one is to complete the release, and the other is to send an exception and release the virtual machine. The second monitorexit in the figure is the process that is executed when an exception occurs, which is what I said at the beginning, "there will be two processes." Also, we can see from the figure that there is a goto instruction on line 13, that is, if the normal operation ends, it will jump to line 19 for execution.
Now, do you know synchronized very clearly? Next, let's talk about Lock.
Lock:Lock implementation is different from synchronized, the latter is a pessimistic lock, it is very timid, it is afraid that someone will grab food with it, so it locks itself up every time it eats. And the bottom layer of Lock is actually the embodiment of CAS optimistic lock, it doesn't matter, someone else robbed it, it would be fine to get it again, so it is very optimistic. Bloggers will not elaborate on how to implement the bottom layer. If I have the opportunity, I will talk to you about the mechanism under the concurrent package. If asked in the interview, you will say that the bottom layer is mainly realized by volatile and CAS operations.
Now, that's what I really want to add at the end of this post. What I want to say is: use synchronized instead of LOCK as much as possible.
What's the concept? Let me give you an analogy: your name is jdk, you gave birth to a child named synchronized, and then you adopted a child named LOCK. At first, when LOCK first came to his new home, he was very good and sensible, and he performed better than synchronized in all aspects. You are happy, but there is a touch of sadness in your heart that you don't want your own child to be less clever than an adopted child. At this time, you educate your own child more deeply, and you want to prove that your own child's synchronized is no worse than the adopted child's LOCK. (the blogger is just speaking metaphorically)
Then how to educate?
In jdk1.6~jdk1.7, when synchronized16 was 7 years old, you, as a father, optimized it for him. Where did you optimize it?
1. Thread spin and adaptive spin
We know that java' threads are actually mapped to the kernel, and thread suspension and recovery can have a great impact on overhead. And jdk officials found that many threads acquire the lock in a very short period of time while waiting for the lock, so they do not need to suspend the thread while waiting, but let it loop aimlessly, usually set 10 times. This avoids the overhead of thread switching and greatly improves performance.
On the other hand, adaptive spin gives spin a kind of learning ability, which is not fixed to spin 10 times. He can adjust its spin according to the spin of the thread in front of it, or even hang it directly without spinning.
2. Lock elimination
What is lock elimination? Is to remove unnecessary synchronization during the compilation phase.
So some of my friends are confused again. I don't know if I want to add a lock to the code I wrote myself. I added the lock to mean that there will be synchronization here?
This is not the case. The lock removal mentioned here does not necessarily refer to the lock elimination of the code you wrote. Let me give you an example:
Before jdk1.5, our String string concatenation was actually implemented by StringBuffer (this can be done by writing a simple demo using the method I introduced earlier, and then looking at the bytecode instructions in the class file), but after jdk1.5, it is concatenated with StringBuilder. Let's consider the previous situation, such as the following code:
String str1= "qwe"; String str2= "asd"; String str3=str1+str2;123
The underlying implementation looks like this:
StringBuffer sb = new StringBuffer (); sb.append ("qwe"); sb.append ("asd"); 123
We know that StringBuffer is a thread-safe class, that is, both append methods are synchronized. Through pointer escape analysis (that is, variables do not leak), we find that there is no thread safety problem in this piece of code, and the synchronization lock will be eliminated at this time.
3. Lock coarsening
When using synchronized, we all pay attention to keeping the synchronization code block as small as possible in order to avoid big overhead. So why make it thicker?
Let's continue to take the above string concatenation as an example, we know that in this piece of code, each append needs to be synchronized once, so I can coarsen the lock to the first append and the last append (don't bother with the lock removal here, I'm just using an analogy)
4. Lightweight lock
5. Bias lock
With regard to the last two, I hope to leave the predestined readers to find them themselves. I don't want me to describe a thing in so much detail. It's your own to get it yourself. What the blogger can tell you is that the last two are not difficult. Come on, guys.
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.