Usage of LockSupport in Java concurrent programming series

  • 2021-12-13 07:59:30
  • OfStack

Directory 1, what is LockSupport? 2. Two kinds of basic API3, LockSupport essence 4, LockSupport example 5, LockSupport source code summary

1. What is LockSupport?

LockSupport is the basic thread blocking primitive for creating locks and other synchronization classes

2. Two basic API

LockSupport Two basic types of API are provided:

block thread class: 1 is usually a method name beginning with pack, pack * (...)

The pack method has two overloaded versions: blocker is an object that specifies which object to block. If you don't know, by default, the lock object itself this is blocker


public static void park();
public static void park(Object blocker);

Expand: parkNanos Function


public static void parkNanos(Object blocker, long nanos) {
    if (nanos > 0) { 
        //  Gets the current thread 
        Thread t = Thread.currentThread();
        //  Settings Blocker
        setBlocker(t, blocker);
        //  Get the license and set the time 
        UNSAFE.park(false, nanos);
        //  Set permissions, reset blocker For null , avoid unpack Obtained by the blocker For the previously set 
        setBlocker(t, null);
    }
}

The nanos parameter represents the relative time, indicating how long to wait

parkUntil Function: Indicates that the current thread is disabled before the specified time limit. deadline parameter indicates absolute time and specified time


public static void parkUntil(Object blocker, long deadline) {
    //  Gets the current thread 
    Thread t = Thread.currentThread();
    //  Settings Blocker
    setBlocker(t, blocker);
    UNSAFE.park(true, deadline);
    //  Settings Blocker For null
    setBlocker(t, null);
}

unBlock Thread class: unpack(Thread)

The unpack method is used to release the license, specifying that the thread can continue to run.

3. LockSupport essence

LockSupport is a licensed semaphore mechanism, pack is consumed, unpack is put in, and only one is put in, which is not accumulated. For example, if you call unpack and put one semaphore into it, you will not accumulate the semaphore if you call it several times, and you will consume it after calling pack

4. Example of LockSupport

Example: How to control two threads to print 1, 2, 3, 4, 5, 6, …


import java.util.concurrent.locks.LockSupport;
public class LockSupportExample {
    private static final int total = 10;
    private  static int i = 0;
    static Thread t1 , t2;
    public static void main(String[] args) {
        t1 = new Thread(() ->{
            while (i < total) {
                System.out.println("t1:" + (++i));
                LockSupport.unpark(t2);
                LockSupport.park();
            }
        });
        t2 = new Thread(() -> {
            while (i < total) {
                LockSupport.park();
                System.out.println("t2:" + (++i));
                LockSupport.unpark(t1);
            }
        });
        t1.start();
        t2.start();
    }
}

Print:

t1: 1
t2: 2
t1:3
t2:4
t1:5
t2:6
t1:7
t2:8
t1:9
t2:10

5. LockSupport source code


public class LockSupport {
    // Hotspot implementation via intrinsics API
    private static final sun.misc.Unsafe UNSAFE;
    private static final long parkBlockerOffset;
    private static final long SEED;
    private static final long PROBE;
    private static final long SECONDARY;
    static {
        try {
            //  Get Unsafe Instances 
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            //  Of the thread class class Object 
            Class<?> tk = Thread.class;
            //  Get Thread Adj. parkBlocker Memory offset address of field 
            parkBlockerOffset = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("parkBlocker"));
            //  Get Thread Adj. threadLocalRandomSeed Memory offset address of field 
            SEED = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSeed"));
            //  Get Thread Adj. threadLocalRandomProbe Memory offset address of field 
            PROBE = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomProbe"));
            //  Get Thread Adj. threadLocalRandomSecondarySeed Memory offset address of field 
            SECONDARY = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
        } catch (Exception ex) { throw new Error(ex); }
    }
}

pack method source code:


public static void park(Object blocker) {
    //  Gets the current thread 
    Thread t = Thread.currentThread();
    //  Settings Blocker
    setBlocker(t, blocker);
    //  Obtain a license 
    UNSAFE.park(false, 0L);
    //  Reset this setting after rerun Blocker For null , avoid unpack Get to on 1 Setting of setBlocker(t, blocker);
    setBlocker(t, null);
}

unpack source code:


public static void unpark(Thread thread) {
    if (thread != null) //  Thread is not empty 
        UNSAFE.unpark(thread); //  Release the thread permission 
}

It can be seen that both the source code of pack and the source code of unpack are implemented through the underlying api of Unsafe

sun.misc.Unsafe Tool classes that can directly perform underlying unsafe operations

It mainly provides the following operations:

Thread Suspend and Resume CAS operation Manipulating object properties Manipulate array elements Direct manipulation of memory

Summarize

This article is here, I hope to give you help, but also hope that you can pay more attention to this site more content!


Related articles: