I. Introduction
Initially intended to analyze ReentrantLock, but in the final analysis, found that without the support of LockSuport, so simply start on the first analysis LockSupport, because it is the basis of the lock, the lock mechanism is a provider of tools, so first be analysis.
Two, LockSupport-source analysis
2.1 properties of the class
public class LockSupport { // Hotspot implementation via intrinsics API private static final sun.misc.Unsafe UNSAFE; // represents the memory offset address private static final long parkBlockerOffset; // represents the memory offset address private static final long SEED; // represents the memory offset address private static final long PROBE; // represents the memory offset address private static final long SECONDARY; static { try { // Get Unsafe examples UNSAFE = sun.misc.Unsafe.getUnsafe(); // Thread class type Class<?> tk = Thread.class; // Get the memory offset address parkBlocker field of Thread parkBlockerOffset = UNSAFE.objectFieldOffset (tk.getDeclaredField("parkBlocker")); // Get the memory offset address threadLocalRandomSeed field of Thread SEED = UNSAFE.objectFieldOffset (tk.getDeclaredField("threadLocalRandomSeed")); // Get the memory offset address threadLocalRandomProbe field of Thread PROBE = UNSAFE.objectFieldOffset (tk.getDeclaredField("threadLocalRandomProbe")); // Get the memory offset address threadLocalRandomSecondarySeed field of Thread SECONDARY = UNSAFE.objectFieldOffset (tk.getDeclaredField("threadLocalRandomSecondarySeed")); } catch (Exception ex) { throw new Error(ex); } } }
Description: UNSAFE field represents sun.misc.Unsafe class, view their source, click here , the general program does not allow direct calls, and the long-type field shows an example of an object corresponding offset address in the memory can be offset by the Gets or sets the value of the address field.
2.2 class constructor
// private constructor can not be instantiated private LockSupport() {}
Description: LockSupport only a private constructor can not be instantiated.
2.3 The core function analysis
Before analysis LockSupport function, introduced first class sun.misc.Unsafe park and unpark function, because the core functions are based LockSupport park and unpark Unsafe functions defined in the class, define two functions is given below.
public native void park(boolean isAbsolute, long time); public native void unpark(Thread thread);
Description: The description of the following two functions
① park function, blocking the thread, and the thread before the event will be blocked following: ① call unpark function, permission to release the thread. ② The thread is interrupted. To set time ③. And, when time is an absolute time, isAbsolute is true, otherwise, isAbsolute is false. When the time is 0 indicates an infinite wait until unpark occur.
② unpark function, permission to release the thread, after the park blocked thread that is activated calls. This function is not safe, this function is called to ensure that the thread is still alive.
1. park function
Overload park function has two versions, the method summarized below
public static void park(); public static void park(Object blocker);
Explanation: The difference between the two functions is that Park () function does not blocker, i.e. the thread is not provided parkBlocker field. park (Object) type functions as follows.
public static void park(Object blocker) { // Get the current thread Thread t = Thread.currentThread(); // set Blocker setBlocker(t, blocker); // Get License UNSAFE.park(false, 0L); // re-we run after this setting Blocker setBlocker(t, null); }
Description: When you call park function, first obtain the current thread, and then set parkBlocker field current thread that calls setBlocker function, after calling the park function Unsafe class, after then call setBlocker function. So the question is, why should this park function to be called twice setBlocker function? The reason is simple, when you call park function, the current thread first set parkBlocker field, and then call Unsafe the park function, after which the current thread has been blocked, waiting unpark function of the thread is called, so the back of a setBlocker function can not run, unpark function is called, after the thread permission, you can continue to run, will run the second setBlocker, the parkBlocker field to the thread is null, thus completing the entire park logic functions. If there is no second setBlocker, then after no call park (Object blocker), and direct calls getBlocker function, or get a blocker before the park (Object blocker) set is obviously illogical. In short, we must ensure that the entire function park (Object blocker) after the implementation of the thread parkBlocker field has returned to null. So, park (Object) type function in setBlocker must call the function twice. setBlocker follows.
private static void setBlocker(Thread t, Object arg) { // Set the thread t arg field value parkBlocker UNSAFE.putObject(t, parkBlockerOffset, arg); }
Description: This method sets the thread t parkBlocker field is arg.
Another overloaded version with no parameters, park () function is as follows.
public static void park() { // obtain a license, setting time is infinite, until you can obtain licenses UNSAFE.park(false, 0L); }
Description: After calling the park function is disabled when the current thread, unless the permit is available. Before one of three things happens, the current thread will be in a dormant state, that is, when the following conditions occur, the current thread will obtain a license, you can continue to run.
① Some other thread the current thread as the target invocation unpark.
② Some other thread interrupts the current thread.
③ The call spuriously (that is, for no reason) returns.
2. parkNanos function
This function disables the current thread permit is available, for up to the specified wait time. Specific functions as follows.
public static void parkNanos(Object blocker, long nanos) { if (nanos> 0) {// time is greater than 0 // Get the current thread Thread t = Thread.currentThread(); // set Blocker setBlocker(t, blocker); // obtain a license and set up time UNSAFE.park (false, nanos); // set permission setBlocker(t, null); } }
Description: This function is called twice setBlocker function, nanos parameter represents the relative time indicates how long to wait.
Function 3. parkUntil
This function disables the current thread until the specified deadline, unless the permit is available. Specific functions as follows.
public static void parkUntil(Object blocker, long deadline) { // Get the current thread Thread t = Thread.currentThread(); // set Blocker setBlocker(t, blocker); UNSAFE.park(true, deadline); // set to null Blocker setBlocker(t, null); }
Description: This function is also called twice setBlocker function, deadline parameter represents the absolute time, represents the specified time.
4. unpark function
This function means that if the given thread license is not available, then make it available. If the thread was blocked on park then it will unblock state. Otherwise, the next call to park will not guarantee to block. If given thread has not been started, it can not guarantee that this operation has no effect. Specific functions as follows.
public static void unpark(Thread thread) { if (thread! = null) // thread is not empty UNSAFE.unpark (thread); // release the thread license }
Explanation: The release license, designated thread can continue to run.
Third, the example shows
3.1 to achieve two thread synchronization
1. wait / notify implemented
package com.hust.grid.leesf.locksupport; class MyThread extends Thread { public void run() { synchronized (this) { System.out.println("before notify"); notify(); System.out.println("after notify"); } } } public class WaitAndNotifyDemo { public static void main(String[] args) throws InterruptedException { MyThread myThread = new MyThread(); synchronized (myThread) { try { myThread.start(); // main thread sleep 3s Thread.sleep(3000); System.out.println("before wait"); // block the main thread myThread.wait(); System.out.println("after wait"); } catch (InterruptedException e) { e.printStackTrace (); } } } }
operation result
before wait before notify after notify after wait
Description: The flow diagram of the specific
When using wait / notify synchronization, you must first call wait, after calling notify, if the first call notify, then call wait, to no effect. Specific code as follows
package com.hust.grid.leesf.locksupport; class MyThread extends Thread { public void run() { synchronized (this) { System.out.println("before notify"); notify(); System.out.println("after notify"); } } } public class WaitAndNotifyDemo { public static void main(String[] args) throws InterruptedException { MyThread myThread = new MyThread(); myThread.start(); // main thread sleep 3s Thread.sleep(3000); synchronized (myThread) { try { System.out.println("before wait"); // block the main thread myThread.wait(); System.out.println("after wait"); } catch (InterruptedException e) { e.printStackTrace (); } } } }
operation result:
before notify after notify before wait
Description: As the first call notify, then call the wait, this time the main thread will always remain blocked.
3.2 park / unpark achieve
package com.hust.grid.leesf.entry; import java.util.concurrent.locks.LockSupport; class MyThread extends Thread { private Object object; public MyThread(Object object) { this.object = object; } public void run() { System.out.println("before unpark"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace (); } // Get blocker System.out.println("Blocker info " + LockSupport.getBlocker((Thread) object)); // release license LockSupport.unpark((Thread) object); // Sleep 500ms, to ensure the execution of the park setBlocker (t, null); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace (); } // Get blocker again System.out.println("Blocker info " + LockSupport.getBlocker((Thread) object)); System.out.println("after unpark"); } } public class test { public static void main(String[] args) { MyThread myThread = new MyThread(Thread.currentThread()); myThread.start(); System.out.println("before park"); // Get License LockSupport.park("ParkAndUnparkDemo"); System.out.println("after park"); } }
operation result:
before park before unpark Blocker info ParkAndUnparkDemo after park Blocker info null after unpark
Description: This program first execution park, and then execute unpark, synchronization, and before and after unpark are called getBlocker, you can see the results of the two are not the same, and the results of the second call is null, this is because after a call to unpark, performed Lock.park (Object blocker) function in setBlocker (t, null) functions, so when the call is null getBlocker second.
The example is to call the park, then call unpark, now modify the program, first call unpark, then call park, see if you can correctly synchronized. Specific code as follows
package com.hust.grid.leesf.locksupport; import java.util.concurrent.locks.LockSupport; class MyThread extends Thread { private Object object; public MyThread(Object object) { this.object = object; } public void run() { System.out.println("before unpark"); // release license LockSupport.unpark((Thread) object); System.out.println("after unpark"); } } public class ParkAndUnparkDemo { public static void main(String[] args) { MyThread myThread = new MyThread(Thread.currentThread()); myThread.start(); try { // main thread sleep 3s Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace (); } System.out.println("before park"); // Get License LockSupport.park("ParkAndUnparkDemo"); System.out.println("after park"); } }
operation result:
before unpark after unpark before park after park
Note: you can see, the earlier call unpark, when then call park, still able to properly synchronized, not caused by the wait / notify calling obstruction caused by improper order. So park / unpark compared to the wait / notify more flexible.
2. Interrupt response
See the following example
package com.hust.grid.leesf.locksupport; import java.util.concurrent.locks.LockSupport; class MyThread extends Thread { private Object object; public MyThread(Object object) { this.object = object; } public void run() { System.out.println("before interrupt"); try { // sleep 3s Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace (); } Thread thread = (Thread) object; // interrupt thread thread.interrupt(); System.out.println("after interrupt"); } } public class InterruptDemo { public static void main(String[] args) { MyThread myThread = new MyThread(Thread.currentThread()); myThread.start(); System.out.println("before park"); // Get License LockSupport.park("ParkAndUnparkDemo"); System.out.println("after park"); } }
operation result:
before park before interrupt after interrupt after park
Note: You can see that in the main thread calls the park blocked, issued the interrupt signal myThread thread, the main thread will continue to run at this time, that is clear at this time interrupt role of the unpark the same.
IV Summary
LockSupport for creating locks and other basic thread synchronization class blocking primitives. In short, when you call LockSupport.park, indicates that the current thread will wait until a license when calling LockSupport.unpark, the thread must wait for permission to get passed as a parameter, so this thread continues to run.