JDK8 analysis of the source code LockSupport

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 

Copy the code

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); }
    }
}

Copy the code

  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.

Copy the code

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);
    }

Copy the code

  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.

Copy the code

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);
        }
    }

Copy the code

  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.  

Copy the code

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);
    }

Copy the code

  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  

Copy the code

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 ();
            }            
        }        
    }
}

Copy the code

  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  

Copy the code

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 ();
            }            
        }        
    }
}

Copy the code

  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 

Copy the code

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");
    }
}

Copy the code

  operation result:  

Copy the code

before park
before unpark
Blocker info ParkAndUnparkDemo
after park
Blocker info null
after unpark

Copy the code

  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  

Copy the code

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");
    }
}

Copy the code

  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  

Copy the code

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");
    }
}

Copy the code

  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.

Published 361 original articles · won praise 370 · views 270 000 +

Guess you like

Origin blog.csdn.net/qq_33589510/article/details/104740390