Explore Java concurrent programming tool: LockSupport, an efficient thread blocking and wake-up mechanism

About the author: CSDN content partner, technical expert, starting from scratch to make tens of millions of daily activities APP.
Focus on sharing original series of articles in various fields, good at java backend, mobile development, artificial intelligence, etc. I hope you will support me a lot.

1. Introduction

We continue to summarize and learn the basics of Java , reviewing the past and learning the new.

2. Overview

LockSupport is a thread synchronization tool class introduced in Java SE 9 and above, which is used to support synchronization methods and provides a variety of synchronization mechanisms.

All methods of LockSupport are static methods, which allow threads to block at any position, and there are corresponding wake-up methods after blocking.
The bottom layer of LockSupport calls the native code in Unsafe.

The underlying locking of many concurrent classes under the java.util.concurrent package is based on LockSupport, such as ReentrantLock, CountDownLatch, ParkableLazyDeque, etc.

3. Usage

The most commonly used methods in the LockSupport class are the Park() and Unpark() methods, which are used to block and wake up threads, respectively.


       Thread a = new Thread(() -> {
    
    

           System.out.println("start " + Thread.currentThread().getName());
           int resule = 0;
           for(int i = 0; i < 10; i ++) {
    
    
               resule += i;
           }
           // 阻塞线程
           LockSupport.park();
           System.out.println(resule);

       }, "a");

       a.start();
       try {
    
    
//            TimeUnit.MILLISECONDS.sleep(1000);
       } catch (Exception e) {
    
    
       }
       
       // 释放,这里不调用的话,上面将一直锁定
       LockSupport.unpark(a);

4. Principle

Both park and unpark directly call the Unsafe method.
We understand this: the principle of these two methods is based on a counter, and the value of the counter determines the blocking waiting state of the thread. When the value of the counter is reduced to 0, it means that the thread can be woken up and perform corresponding operations.

In addition, LockSupport also provides some synchronization methods, such as Lock and Unlock() methods, for acquiring and releasing locks. The Lock method is used to acquire the lock, and the Unlock() method is used to release the lock. Different from the synchronized keyword, the Lock and Unlock() methods do not need to be executed at the same time. The lock can be acquired in any method and the lock can be released in any method, so it is more flexible and convenient.


    调用park后,此时线程处于waiting的状态
    
    public static void park() {
    
    
        UNSAFE.park(false, 0L);
    }
    
    public static void park(Object blocker) {
    
    
        // 获取当前线程
        Thread t = Thread.currentThread();
        
        // 设置Blocker
        setBlocker(t, blocker);
        
        // 此后,当前线程就已经阻塞了,后面的函数无法运行,直至unpark函数被调用
        UNSAFE.park(false, 0L);
        
        //unpark函数被调用后,继续执行,如果没有第二个setBlocker,那么之后没有调用park(Object blocker),
        //而直接调用getBlocker函数,得到的还是前一个park(Object blocker)设置的blocker,显然是不符合逻辑的
        setBlocker(t, null);
    }
    
    public static void unpark(Thread thread) {
    
    
        if (thread != null)
           UNSAFE.unpark(thread);
    }

Unsafe.java


    public native void unpark(Object var1);

    public native void park(boolean var1, long var2);

Five, the method of thread waiting and waking up

5.1 LockSupport.park()

    // Hotspot implementation via intrinsics API
    private static final sun.misc.Unsafe UNSAFE;
    
    static {
    
    
        try {
    
    
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            
        } catch (Exception ex) {
    
     throw new Error(ex); }
    }

The difference between Thread.sleep() and LockSupport.park()

Both Thread.sleep() and LockSupport.park() block the execution of the current thread,
and neither will release the lock resource occupied by the current thread;

  • Thread.sleep() cannot wake up from the outside, but can only wake up by itself; it is a native method in itself;
  • The LockSupport.park() method can be awakened by another thread calling the LockSupport.unpark() method; * The bottom layer is the native method of calling Unsafe;

The Thread.sleep() method needs to catch interrupt exceptions.
LockSupport.park() does not need to catch interrupt exceptions.

5.2 wait(), notify, notifyAll in Object

The wait, notify, and notifyAll methods in the Object class are used for thread waiting and waking up, and must be executed inside sychronized

Principle of Object.wait()

In the Object.wait() method, first use the synchronized keyword to lock the current object, and then call the Object.wait() method to wait for another thread to complete and return a Future object. During the waiting process, the current thread will be blocked until another thread finishes executing and returns a Future object. When the waiting thread finishes executing, the get() method of the Future object will return the result of the waiting thread. Therefore, when using the Object.wait() method, you need to ensure that the waiting thread has finished executing, otherwise it may cause problems such as deadlock.

5.3 The await() method of Condition

Condition in Java is an interface under the java.util.concurrent.locks package, which is mainly used to control the waiting and waking up of threads in a multi-threaded environment.

The thread needs to acquire and hold the lock, and must wait and wake up in the lock block (synchronized or lock)
before the thread can be woken up.

5.4 Difference between Thread.sleep() and Object.wait()

Thread.sleep() will not release the lock resource, it will wake up automatically when the time comes, and then continue to execute;
Object.wait() will release the lock resource. Another thread needs to be woken up using Object.notify()

5.5 Difference between Object.wait() and LockSupport.park()

Both will block the execution of the current thread.

  • The Object.wait() method needs to be executed in a synchronized block;

  • LockSupport.park() can be executed anywhere;

  • The Object.wait() method needs to catch interrupt exceptions.

  • LockSupport.park() does not need to catch interrupt exceptions.

  • Object.wait() without timeout requires another thread to execute notify() to wake up, but it does not necessarily continue to execute subsequent content;

  • If LockSupport.park() does not have a timeout, another thread needs to execute unpark() to wake it up, and it will continue to execute subsequent content;

5.6 Difference between Object.wait() and Condition.await()

The principles of Object.wait() and Condition.await() are basically the same, the difference is that the bottom layer of Condition.await() is to call LockSupport.park() to block the current thread.

5.7 In java, why should methods such as notify/wait be executed in a synchronous code block

Synchronized code blocks are usually decorated by the synchronized keyword
In Java, the notify() and wait() methods are usually used to implement communication and synchronization between threads. These methods are usually executed in a synchronized code block to ensure thread safety and atomicity.
Executing notify() and wait() methods in a synchronized code block can ensure thread safety and atomicity, because they can guarantee that only one thread can execute these methods at a time. If these methods are executed in an unsynchronized code block, it may cause problems such as race conditions and deadlocks.

5.8 What happens if notify() is executed before wait()?

If the current thread is not the owner of the object lock, an IllegalMonitorStateException is thrown when the notify() or wait() method of the object is called; if the
current thread is the owner of the object lock, wait() will always block because there will be no other notify() to wake it up.

5.8 What happens if unpark() is executed before park()?

The thread will not be blocked, skip park() directly, and continue to execute the follow-up content, you can try it yourself


        Thread a = new Thread(() -> {
    
    

            System.out.println("start " + Thread.currentThread().getName());
            int resule = 0;
            for(int i = 0; i < 10; i ++) {
    
    
                resule += i;
            }
            LockSupport.park();
            System.out.println(resule);

        }, "a");

        try {
    
    
//            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (Exception e) {
    
    
        }
        LockSupport.unpark(a);
        a.start();
        LockSupport.unpark(a);

6. Recommended reading

Java column

SQL column

Data Structures and Algorithms

Android Learning Column

Guess you like

Origin blog.csdn.net/fumeidonga/article/details/131713707