LockSupport详解

LockSupport详解

简介

  • LockSupport用来创建锁或其他同步类的基本线程阻塞原语.
  • 调用park()方法时,当前线程将等待,直到获取许可.
  • 调用unpark()方法时,必须将等待获得许可的线程作为参数,使得等待的线程继续进行.

核心方法

Unsafe类的park和unpark

LockSupport的park()unpark()是调用Unsafe类的park()unpark()实现的.

  • park():阻塞线程.
  • unpark():释放线程,激活调用park()后阻塞的线程.

park()方法

// 调用park后线程会被阻塞,三种情况下线程获得许可:
// 1. 其他线程调用此线程的unpark()
// 2. 其他线程中断此线程
// 3. 该调用无理由返回
public static void park(Object blocker) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker); // 设置当前线程的blocker
    UNSAFE.park(false, 0L); // 阻塞当前线程
    setBlocker(t, null); // 设置当前线程的blocker为null
}

注:(调用两次设置blocker的原因)
首次设置好blocker后,调用park()阻塞线程,等待其他线程调用unpark()来激活线程.
当前线程再次被激活后,再次设置blocker为null.否则,在获取blocker时,得到的是上一次设置的blocker.

parkNanos

在许可可用前阻塞当前线程,最多等待指定的等待时间.

parkUntil

在指定时限前禁止当前线程,除非许可可用.

unpark

  • 若给定线程的许可不可用,则使其可用,解除阻塞状态.
  • 若线程未启动,则无效果.

使用park/unpark实现线程同步

示例:

// 一个park阻塞的线程,被其他线程unpark()后继续执行
threadA t1 = new threadA();

t1.start();

LockSupport.unpark(t1);

// t1.interrupt(); // 中断park的线程也可将其唤醒

// --------------------
class threadA{
    Thread.sleep(1000); // 先unpark,再park一样可行
    LockSupport.park();
    System.out.println(Thread.currentThread().getName());
}
// 先对一个线程unpark(),然后其调用park()后,线程继续执行
threadA t1 = new threadA();

t1.start();



LockSupport.unpark(t1);

// t1.interrupt(); // 中断park的线程也可将其唤醒

// --------------------
class threadA{
    LockSupport.park();
    System.out.println(Thread.currentThread().getName());
}

小结

Thread.sleep()与Object.wait()的区别

Thread.sleep() Object.wait()
不会释放占有的锁 会释放占有的锁
参数 必须传入睡眠的时间 可以传时间,也可不传
时间 时间到了会自动唤醒,继续执行 没有时间,需要等待notify唤醒;有时间,则被唤醒或时间到了自动唤醒

Thread.sleep()与Condition.await()的区别

基本相同,Condition.await()是调用LockSupport.part()阻塞当前线程.

流程:

  1. 将当前线程加入条件队列.
  2. 释放锁.
  3. 调用LockSupport.park()阻塞当前线程.

Thread.sleep()和LockSupport.park()的区别

Thread.sleep() LockSupport.park()
功能 阻塞当前线程,不释放占有的锁 阻塞当前线程,不释放占有的锁
唤醒 只能自己唤醒自己 可以被其他线程通过unpark()唤醒
异常 声明抛出异常 不需要捕获异常

Object.wait()和LockSupport.park()的区别

Object.wait() LockSupport.park()
使用 只能在synchronized块执行 在任意地方执行
异常 声明抛出中断异常 不需要捕获异常
超时 不带超时,需要其他线程执行notify()唤醒 不带超时,需要其他线程执行unpark()唤醒
睡眠前唤醒 抛出异常 不会被阻塞,跳过park(),继续执行

参考:

原文地址:https://www.cnblogs.com/truestoriesavici01/p/13224742.html