Introduction:
I saw the use of lock yesterday when I was learning about the interview experience shared by others. Think of myself in the last interview also encountered the difference between synchronized and lock and use. So I sorted out the difference and use of the two, at the same time, the use of synchronized some common problems of the summary, and finally the reference source and documentation, the use of lock wrote a few simple demo. Please criticize me.
Technical points:
1. Threads and processes:
To distinguish a process from a thread before you start, a program requires at least one process, and a process requires at least one thread. A relationship is the approximate composition of a thread-–> process –> program. So the thread is the smallest unit of the program execution flow, and the process is an independent unit of resource allocation and scheduling for the system. All of the discussions below are built on a thread basis.
2, several important methods of thread:
Let's take a look at some important methods of thread. A, the start () method, which calls the method to start executing the thread, B, the Stop () method, which is invoked to force the end of the thread execution; C, join method, which calls the method to wait for the thread to end. D, Sleep () method, which calls the method that the thread enters the wait. E, run () method, calling this method directly executes the thread's run () method, but the thread calls the start () method to run the run () method, which is the difference between running the run () method by a thread dispatch, and a direct call to the run () method in the thread ...
See here, some people may ask, that wait () and notify (). Note that the wait () and notify () method is the object method, not the thread method. At the same time, wait () and notify () are used in conjunction with each other to indicate thread suspension and thread recovery.
Here's a very common question, incidentally: the difference between wait () and sleep () is simply that wait () releases the object Lock and sleep () does not release the object lock. There is a lot of information on these issues and we are not going to repeat them.
3, Thread State:
The thread has a total of 5 states, which is easy to understand by introducing the second knowledge point above.
New state: New Thread object, before the start () method is invoked
Ready state: The thread enters the ready state after invoking the start () method, but it does not mean that the call to the start () method thread immediately becomes the front, and is ready before it becomes the front. It's worth mentioning that threads get ready when they're back in sleep and hang.
Run state: The thread is set to the current thread and the run () method is started. is when the thread enters the running state
Blocking state: Thread is paused, for example, after calling the sleep () method, the thread enters the blocking state
Death Status: Thread Execution end
4. Lock type
Reentrant Locks: All synchronization methods in the executing object do not have to acquire locks again
Interruptible locks: interruptible while waiting for lock to be acquired
Fair Lock: The waiting time of the thread waiting to acquire the lock is obtained, the waiting time has the priority to acquire the lock right
Read and Write Lock: The resources read and write when split into 2 parts processing, read the time can be multithreaded to read together, write the time must be synchronized to write synchronized and lock the difference between
1, I classify the difference between the two to a table, convenient for everyone to compare:
category |
synchronized |
Lock |
Existence level |
Java keywords, on the JVM level |
is a class |
Release of the Lock |
1, the thread to get the lock to complete the synchronization code, release the lock 2, the thread execution occurs abnormally, the JVM will let the thread release the lock |
Locks must be released in Finally, or thread deadlocks are easily caused |
Acquisition of Locks |
Let's say a thread gets the lock and b thread waits. If a thread is blocked, the B thread waits |
In the case of the situation, lock has more than one lock to obtain the way, specifically below will say, basically can try to get the lock, the thread can not have to wait |
Lock status |
Can't judge |
Can judge |
Lock type |
Can be reentrant not interrupted unfair |
can be re-entry can be judged fair (both) |
Performance |
Small number of synchronizations |
Mass Sync |
Perhaps, seeing here is still little known about lock, then we go into the deep study of lock. Lock Detailed Introduction and demo
The following is the source of the lock interface, the author after the result of pruning:
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's free in the time of
invocation.
* *
Boolean trylock ();
/**
* Acquires the lock if it's free within the given waiting time and the
* current thread has not been {@link Plain Thread#interrupt interrupted}.
* *
Boolean Trylock (long time, Timeunit unit) throws interruptedexception;
/**
* Releases the lock.
* *
void unlock ();
}
From the lock interface we can see that there is a main method, the function of these methods can be seen from the annotation:
Lock (): Gets the lock and waits if the lock is taken up
Unlock (): Release lock
Trylock (): Note that the return type is Boolean, return False if the lock is occupied when the lock is acquired, or else true
Trylock (long, timeunit unit): Compared to the Trylock () is to give a time limit to ensure that the waiting parameter time
Lockinterruptibly (): With the way the lock is obtained, if the thread enters the wait at the stage of acquiring the lock, you can break the thread and do something else first.
Through the explanations above, roughly explained in the last section of the "Lock type (lockinterruptibly ())", "Lock Status (Trylock ())" and other issues, as well as the process of acquiring the face before I wrote "is basically can try to get the lock, the thread can not wait all the time" used The reason for "can".
The following is a general example of lock usage, noting that Reentrantlock is the implementation of the lock interface.
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 () + "acquired lock");
}catch (Exception e) {e.printstacktrace ();
finally {System.out.println ("Thread Name" +thread.getname () + "release lock");
Lock.unlock ();
} public static void Main (string[] args) {locktest locktest = new Locktest ();
Threads 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.me
Thod (Thread.CurrentThread ()); }, "T2");
T1.start ();
T2.start (); }//execution: Thread name T1 acquired lock//thread name T1 freed lock//thread name T2 acquired lock//thread name T2 released lock
Trylock ():
Package com.brickworkers;
Import Java.util.concurrent.locks.Lock;
Import Java.util.concurrent.locks.ReentrantLock;
public class Locktest {private lock lock = new Reentrantlock ();
Methods required to participate in synchronization private void method (thread thread) {/* Lock.lock ();
try {System.out.println ("Thread Name" +thread.getname () + "acquired lock");
}catch (Exception e) {e.printstacktrace ();
finally {System.out.println ("Thread Name" +thread.getname () + "release lock");
Lock.unlock ();
}*/if (Lock.trylock ()) {try {System.out.println ("Thread Name" +thread.getname () + "acquired lock");
}catch (Exception e) {e.printstacktrace ();
finally {System.out.println ("Thread Name" +thread.getname () + "release lock");
Lock.unlock ();
}else{System.out.println ("I Am" +thread.currentthread (). GetName () + "Someone is holding the lock, I don't want It"); }} public static void Main (STring[] args {locktest locktest = new Locktest ();
Threads 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.me
Thod (Thread.CurrentThread ());
}, "T2");
T1.start ();
T2.start ();
}//Execution result: Thread name T2 got the lock//I'm T1 someone's holding the lock, I don't want it//thread name T2 released lock
See here believe everyone will also use lock, about Trylock (long time, Timeunit unit) and lockinterruptibly () no longer repeat. The former mainly has a waiting time, in the test code to write a wait time, the latter is mainly waiting for interrupts, will throw a break anomaly, often not high, like to explore their own in-depth study.
The previous comparison refers to the "fair lock", where you can mention the Reentrantlock for the definition of a balanced lock, in the source code there are two paragraphs:
/** * Sync object for Non-fair locks/static final class Nonfairsync extends Sync {private stat
IC 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.cu
Rrentthread ());
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.
*/ 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; }
}
From the above source can be seen in lock can control the lock is fair, and, the default is not fair lock, the following is the Reentrantlock constructor:
Public Reentrantlock () {
sync = new Nonfairsync ();//default non-fair lock
}
Tail Record:
The author level general, but this blog in the introduction of the purpose has been achieved. This is only the author in the learning process of the summary and summary, if there is not correct, you are welcome to criticize the point.
Extended Learning: For the implementation of lock bottom, you can refer to:
Click on lock bottom to introduce blog
Two methods of synchronization performance testing, you can refer to:
Click to view two types of synchronization performance test blog blogger March 18 NEW:
Come back to see your blog. The discovery of things is not complete enough. Here to add, because this blog access is larger, so in order not to mislead everyone, as far as possible to introduce to everyone the correct statement:
1, two kinds of lock of the bottom implementation mode:
Synchronized: We know Java is using bytecode directives to control programs (this does not include hot code compiled into machine code). In a byte instruction, there is a block of code contained in the synchronized, which will result in the execution of 2 steps.
We click to view the Syncdemo.java source Syncdemo.class, you can see the following:
As above is this code section bytecode instructions, not as difficult as you think it. To get to the big picture, we can see clearly that the synchronized mapping into bytecode instructions is an increase of two instructions: Monitorenter and monitorexit. When a thread executes a monitorenter instruction, it will try to get the lock, and if the lock is obtained then the lock counts +1 (why add one, because it is a reentrant lock, so it needs to be judged with this lock count), if the lock is not obtained, then the blocking. When it encounters Monitorexit, the lock counter-1, when the counter is 0, then release the lock.
So some friends see here on the doubt, the picture has 2 monitorexit ah. Immediately answer this question: Above I have written the article also has stated, the synchronized lock release has two kinds of mechanisms, one is executes the release, another kind is sends the exception, the virtual machine releases. The second monitorexit in the diagram is the process that executes when an exception occurs, which is what I said at the beginning of "there will be 2 processes present." Also, from the diagram we can see that on line 13th, there is a goto instruction, which means that if the end of the normal run will jump to 19 lines to execute.
Now, do you have a clear understanding of synchronized? Next we'll talk about lock.
Lock:lock implementation and synchronized is not the same, the latter is a pessimistic lock, it is very timid, it is very afraid of someone and it grab food, so it every time before eating things shut themselves up. And lock the bottom is actually the embodiment of CAs optimistic lock, it does not matter, others robbed it to eat, it again to get food is good, so it is very optimistic. Concrete bottom How to achieve, Bo Master not in detail, have the opportunity, I will concurrent package under the mechanism of good and everyone said, if the interview asked, you said the bottom of the main rely on volatile and CAS operation.
Now, that's what I really want to add behind this post, what I'm saying is: Try to use synchronized instead of lock
What kind of concept. I would like to make an analogy: you call JDK, you have a child named synchronized, later, you adopted a child called lock. At first, lock just came to a new home, it is very well-behaved, very sensible, all aspects of performance than synchronized better. You are happy, but deep inside you have a little bit of sadness, you do not want your own child even worse than an adopted child well-behaved. At this time, you are more profound to the birth of the child, you want to prove that your biological child is not synchronized than the adoption of the child lock poor. (The blogger is just a metaphor)
So how to educate.
In jdk1.6~jdk1.7, that is, SYNCHRONIZED16, 7 years old, you as a father, you gave him optimization, where is the specific optimization:
1. Thread Spin and adaptive spin
We know that Java ' threads are actually mapped on top of the kernel, and that thread hangs and restores can have a significant impact on overhead. and JDK official found that many threads in the waiting for the lock, in a very short period of time to acquire the lock, so they wait on the line, do not need to hang the thread, but let his endless loop, generally set 10 times. This avoids the overhead of thread switching and greatly improves performance.
And adaptive spin, is given to spin a learning ability, it does not fixed spin 10 times. He can adjust its spin according to the spin of the thread in front of it, and even hang it directly without spinning.
2, Lock elimination
What do you mean, lock elimination? is to remove unnecessary synchronization in the compile phase.
Then some friends are confused, I wrote the code I will not know if you want to lock. I added a lock means that there will be synchronization.
Not so, the lock elimination is not necessarily referred to as the lock elimination of the code you write, I would like to make an analogy:
Before jdk1.5, our string string concatenation operation actually the bottom is stringbuffer to realize (this everybody can use the method which I introduced earlier, writes a simple demo, then looks at the byte code instruction in the class file to be clear), but after jdk1.5, then is uses the STRINGB Uilder to the stitching. We consider the previous case, such as the following code:
String str1= "Qwe";
String str2= "ASD";
String str3=str1+str2;
The underlying implementation becomes this:
StringBuffer sb = new StringBuffer ();
Sb.append ("Qwe");
Sb.append ("ASD");
We know that StringBuffer is a thread-safe class, that is, two append methods will be synchronized, through the pointer Escape analysis (that is, the variable does not leak), we found that the code does not exist thread safety problems, this time will be the synchronization lock elimination.
3, Lock coarsening
In the use of synchronized, we are fastidious in order to avoid large overhead, as far as possible synchronized code block to small. So why do you have to make it thicker?
We continue with the string concatenation above as an example, we know that in this piece of code, each append need to sync once, then I can rough the lock to the first append and the last append (here do not tangle the front lock elimination, I just for example)
4. Lightweight lock
5. Bias Lock
On the last two, I hope to leave the reader to find their own, I do not want me to describe a thing so detailed, their hands to get is your own, bloggers can tell you that the last two are not difficult. Come on, guys.