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
核心流程图
使用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