LockSupport和Object中wait/notify的异同点

先说结论
共同点
  • LockSupport中的park方法和Object中的wait方法都可以使线程进入WAIT或者TIMED_WAIT状态
  • LockSupport中的unpark方法和Object中的notify可以使线程脱离WAITTIMED_WAIT状态
  • 二者都可以通过调用线程的interrupt方法脱离等待状态
  • 两者都是通过JVM层,也就是native代码实现的
不同点
  • Object中的wait方法在调用时当前线程必须要对该Object进行加锁,否则会抛出IllegalMonitorException。而LockSupport无需加锁,直接调用其静态方法park就可以使当前线程进入阻塞状态。
  • Objectwaitnotify方法必须要按顺序调用,如果因为线程调度问题导致线程A先调用notify方法而线程B后调用wait方法,那么会使线程A永远处于WAIT状态。对于LockSupport而言则没有这种限制,如果有线程A首先调用了unpark方法并传入了线程B的引用,然后线程B再调用了park方法,那么线程B是不会进入等待状态的。
  • 调用Objectwait方法后,可以调用该线程的interrupt方法脱离等待状态并捕获InterruptedException。而LockSupport的并不能捕获InterruptedException

下面我们简单介绍一下两者:

LockSupport

LockSupport定义了以下静态方法:

方法签名作用
void unpark(Thread thread)唤醒指定的线程
void park()使当前线程进入等待状态,如果之前调用过unpark方法并传入当前线程,那么不会等待
void park(Object blocker)同park方法,只不过传入一个对象放置于该线程的parkBlocker成员变量
void parkNanos(long nanos)同park方法,最多使当前线程等待nanos纳秒
void parkNanos(Object blocker, long nanos)同parkNanos方法,并设置当前线程的parkBlocker成员变量
void parkUntil(long deadline)同park方法,等待到指定的时间戳(也就是指定一个绝对时间)
void parkUntil(Object blocker, long deadline)同上述parkUntil方法,并设置当前线程的parkBlocker成员变量
Object getBlocker(Thread t)获取线程t的parkBlocker成员变量

上述方法不仅可以使当前线程进入等待状态,还可以设置一个对象赋给线程的parkBlocker对象,这个对象一般用于问题排查和系统的监控。

需要注意的是,在调用park方法并传入blocker对象后,只要该线程一直处于等待状态,都可以通过getBlocker方法获得该对象,但是当线程脱离上述状态后,就会将parkBlocker成员变量设为null

LockSupportpark方法和unpark方法在JDK1.8中是基于sun.misc.Unsafe实现的,Unsafe直接提供了parkunpark方法,它们都是native方法,并在JVM层实现。

在上文我们对比ObjectLockSupport时,我们提到了LockSupport的唤醒和等待可以乱序调用而不会时线程进入等待状态。这是因为Thread底层的Parker对象维护了一个许可,当首先调用unpark方法时,相当于给了这个线程一个许可,当再次调用park方法时,线程发现已经持有了这个许可后就不会进入等待状态了;如果线程发现没有许可,就会进入等待状态。

Object的wait/notify

在调用一个Object对象的wait方法时必须时当前线程对该对象加锁:

synchronized(obj) {
	obj.wait();
}

wait方法在底层可以分为三个步骤:

  1. 解除当前对象的锁
  2. 进入WAIT状态,等待唤醒(或interrupt中断线程)
  3. 不论是通过notifynotifyAll唤醒线程,还是通过interrupt方法脱离等待状态(即使捕获InterruptedException的逻辑不在同步代码中),都会使该线程重新竞争该对象的锁,在重新得到锁前线程会处于BLOCKED状态。

调用notify/notifyAll方法同样需要获得锁,它会将JVM内部某个变量作一个标记,使线程唤醒。

notify方法是非公平的,会随机唤醒一个正在等待这个锁的线程。类似于AQSCondition,每个Object对象内部都可以持有一个等待队列,这个等待队列可以存放在该对象等待的线程,从而实现Objectwait/notify机制。源码分析可以参考这篇文章:https://www.jianshu.com/p/f4454164c017

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值