JUC的LOCK框架系列二LOCK框架之LockSupport

Posted 顧棟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC的LOCK框架系列二LOCK框架之LockSupport相关的知识,希望对你有一定的参考价值。

LockSupport

源码采用JDK8

文章目录

  • 为什么LockSupport也是核心基础类? AQS框架借助于两个类:Unsafe(提供CAS操作)和LockSupport(提供park/unpark操作)
  • 写出分别通过wait/notify和LockSupport的park/unpark实现同步?
  • LockSupport.park()会释放锁资源吗? 那么Condition.await()呢?
  • Thread.sleep()、Object.wait()、Condition.await()、LockSupport.park()的区别? 重点
  • 如果在wait()之前执行了notify()会怎样?
  • 如果在park()之前执行了unpark()会怎样?

主要方法

LockSupport定义了一组公共静态方法,这些方法提供了最基础的线程阻塞和唤醒功能。park开头的代表阻塞,unpark开头的代表唤醒。

方法名说明
void park(Object blocker)blocker标识当前线程正在等待的对象(阻塞对象)。阻塞当前线程,在调用unpark和当前线程被中断才能返回
void parkNanos(Object blocker, long nanos)blocker标识当前线程正在等待的对象(阻塞对象)。阻塞当前线程,最长不超过nanos纳秒。被阻塞的线程会在超时后自动唤醒返回
void parkUntil(Object blocker, long deadline)blocker标识当前线程正在等待的对象(阻塞对象)。阻塞当前线程,直到deadline时间(从1970年到deadline时间的毫秒数)
void park()阻塞当前线程,在调用unpark和当前线程被中断才能返回
void parkNanos(long nanos)阻塞当前线程,最长不超过nanos纳秒。被阻塞的线程会在超时后自动唤醒返回
void parkUntil(long deadline)阻塞当前线程,直到deadline时间
void unpark(Thread thread)唤醒处于阻塞状态的线程

注意:拥有参数blocker的方法,在被阻塞的时候,在dump文件中会展示当前线程的正在等待的锁(阻塞对象)。

源码部分

LockSupport的构造函数与成员

public class LockSupport 
    // 私有的构造函数,代表类不可以实例化
    private LockSupport()  // Cannot be instantiated.

...
...
...

    // 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 
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            // 线程类类型
            Class<?> tk = Thread.class;
            parkBlockerOffset = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("parkBlocker"));
            SEED = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSeed"));
            PROBE = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomProbe"));
            SECONDARY = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
         catch (Exception ex)  throw new Error(ex); 
    


park(Object blocker)

    public static void park(Object blocker) 
        // 获取当前线程
        Thread t = Thread.currentThread();
        // 第一次设置阻塞对象,当前线程等待这个对象
        setBlocker(t, blocker);
        // 执行后,线程就进入了阻塞状态,直到出现以下情况才被唤醒
        // 1.其他线程执行了unpark(当前线程)来唤醒
        // 2.其他线程中断了当前线程
        // 3.虚假调用(无理由)返回。线程不存在了???
        UNSAFE.park(false, 0L);
        // 第二次设置阻塞对象,此时线程以及被唤醒,所以需要清空阻塞对象
        setBlocker(t, null);
    

parkNanos(Object blocker, long nanos)

    public static void parkNanos(Object blocker, long nanos) 
        // 等待时长需要大于0
        if (nanos > 0) 
            // 获取当前线程
            Thread t = Thread.currentThread();
            // 第一次设置阻塞对象,当前线程等待这个对象
            setBlocker(t, blocker);
            // 执行后,线程就进入了阻塞状态,直到出现以下情况才被唤醒
            // 1.其他线程执行了unpark(当前线程)来唤醒
            // 2.其他线程中断了当前线程
            // 3.等待的时间超时了
            // 4.虚假调用(无理由)返回。线程不存在了???
            UNSAFE.park(false, nanos);
            // 第二次设置阻塞对象,此时线程以及被唤醒,所以需要清空阻塞对象
            setBlocker(t, null);
        
    

parkUntil(Object blocker, long deadline)

    public static void parkUntil(Object blocker, long deadline) 
        // 获取当前线程
        Thread t = Thread.currentThread();
        // 第一次设置阻塞对象,当前线程等待这个对象
        setBlocker(t, blocker);
        // 执行后,线程就进入了阻塞状态,直到出现以下情况才被唤醒
        // 1.其他线程执行了unpark(当前线程)来唤醒
        // 2.其他线程中断了当前线程
        // 3.时间到达deadline
        // 4.虚假调用(无理由)返回。线程不存在了???
        UNSAFE.park(true, deadline);
        // 第二次设置阻塞对象,此时线程以及被唤醒,所以需要清空阻塞对象
        setBlocker(t, null);
    

unpark(Thread thread)

    public static void unpark(Thread thread) 
        // 线程为不空
        if (thread != null)
            // 释放该线程许可
            UNSAFE.unpark(thread);
    

使用示例

Object的wait和notify

public class WaitAndNotifyDemo 

    static class MyThread extends Thread
        @Override
        public void run() 
            // 锁MyThread的实例对象myThread
            synchronized (this) 
                System.out.println("获取锁的当前线程[" + Thread.currentThread().getName() + "] before notify");
                notify();
                System.out.println("获取锁的当前线程[" + Thread.currentThread().getName() + "] after notify");
            
        
    

 public static void main(String[] args) throws InterruptedException 
        MyThread myThread = new MyThread();
        // 锁这个对象myThread
        synchronized (myThread) 
            try 
                myThread.start();
                // 主线程睡眠3s
                Thread.sleep(3000);
                System.out.println("获取锁的当前线程[" + Thread.currentThread().getName() + "] before wait");
                // 阻塞主线程
                myThread.wait();
                System.out.println("获取锁的当前线程[" + Thread.currentThread().getName() + "] after wait");
             catch (InterruptedException e) 
                e.printStackTrace();
            
        
    


结果

获取锁的当前线程[main] before wait
获取锁的当前线程[Thread-0] before notify
获取锁的当前线程[Thread-0] after notify
获取锁的当前线程[main] after wait

核心流程图

main myThread对象锁 Thread0 【运行状态】 创建线程 myThread 【新建状态】 获取myThread对象锁 成功获取myThread对象锁 启动myThread 【就绪状态】 【运行状态】 synchronized (this) 获取myThread对象锁 获取myThread对象锁失败 【阻塞状态】 获取锁失败 【阻塞状态】 Thread.sleep(3000) 【阻塞状态】 myThread.wait() 释放myThread对象锁 成功释放myThread对象锁 获取myThread对象锁 成功获取myThread对象锁 【就绪状态】 获取锁成功 【运行状态】 唤醒wait阻塞的线程mian\\n notify 【就绪状态】 释放myThread对象锁 成功释放myThread对象锁 【死亡状态】 获取myThread对象锁 成功获取myThread对象锁 【运行状态】 释放myThread对象锁 成功释放myThread对象锁 【死亡状态】 main myThread对象锁 Thread0

使用wait/notify实现同步时,必须先调用wait,后调用notify,如果先调用notify,再调用wait,将起不了作用。

LockSupport的park和unpark

import java.util.concurrent.locks.LockSupport;

public class LockSupportDemo 

    static class MyThread extends Thread 
        // 线程对象
        private Object object;

        public MyThread(Object object) 
            this.object = object;
        

        @Override
  

以上是关于JUC的LOCK框架系列二LOCK框架之LockSupport的主要内容,如果未能解决你的问题,请参考以下文章

JUC系列LOCK框架系列之五 核心锁类AbstractQueuedSynchonizer

JUC系列LOCK框架系列之四 同步工具类Semaphore

JUC系列LOCK框架系列之七 核心锁类之ReentrantReadWriteLock

JUC系列LOCK框架系列之六 核心锁类之ReentrantLock

JUC的LOCK框架系列一LOCK框架预览

Java并发编程系列之三JUC概述