JUC 高并发编程(13):LockSupport 概述, wait 与 sleep与park的区别

LockSupport

LockSupport 是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,阻塞之后也有对应的唤醒方法。归根结底,LockSupport调用的Unsafe中的native代码

  • 通过park()和unpark(thread)方法来实现阻塞和唤醒线程的操作
  • LockSupport类使用了一种名为 Permit(许可) 的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit),permit只有两个值 1和零,默认是零
    在这里插入图片描述
    注意上面的123方法,都有一个blocker,这个blocker是用来记录线程被阻塞时被谁阻塞的。用于线程监控和分析工具来定位原因的。

① 阻塞方法

permit默认是0,所以一开始调用park()方法,当前线程就会阻塞,直到别的线程将当前线程的permit设置为1时, park方法会被唤醒,然后会将permit再次设置为0并返回permit 表示当前线程是否处于运行状态

  • static void park( ):底层是unsafe类native方法
    在这里插入图片描述
  • static void park(Object blocker)
    在这里插入图片描述
  • blocker是用来记录线程被阻塞时被谁阻塞的。用于线程监控和分析工具来定位原因的。setBlocker(t, blocker) 方法的作用是记录t线程是被broker阻塞的。

② 唤醒方法(注意这个permit最多只能为1)

调用 unpark(thread) 方法后,就会将 thread 线程的许可 permit设置成1(注意多次调用unpark方法,不会累加,permit值还是1)会自动唤醒thread线程,即之前阻塞中的 LockSupport.park()方法会立即返回。
在这里插入图片描述

park, wait, sleep, interrupt, yeild 对比

JVM线程状态: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED

  • BLOCKED:是等待获得对象锁
  • WAITING是调用了:wait, sleep, park
    在这里插入图片描述

1. 线程让步: yield()

yield() 的作用是让步。它能让当前线程由“运行状态”进入到“就绪状态”,从而让其它具有相同优先级的等待线程获取执行权

  • 但是,并不能保证在当前线程调用 yield() 之后,其它具有相同优先级的线程就一定能获得执行权;
  • 也有可能是当前线程又进入到“运行状态”继续运行!
  • 在操作系统层面让线程从running变成ready状态,等待继续被调度。在jvm的线程状态还是RUNNABLE

2、阻塞线程,并且释放锁: Object中的wait()和notify()

  • 进入 TIMED_WAITING 状态,让出锁并进入对象的等待
  • 因为wait需释放锁,所以必须在synchronized中使用(没有锁时使用会抛出IllegalMonitorStateException)
  • notify也要在synchronized使用,并且应该指定对象
  • synchronized(),wait(),notify() 对象必须一致,一个synchronized()代码块中只能有1个线程wait()或notify()

3、线程休眠:sleep()

  • sleep() 定义在Thread.java中。
  • sleep() 的作用是让当前线程休眠,即当前线程会从“运行状态”进入到“休眠(阻塞)状态”。
  • sleep()会指定休眠时间,线程休眠的时间会大于/等于该休眠时间;在线程重新被唤醒时,它会由“阻塞状态”变成“就绪状态”,从而等待cpu的调度执行
  • 进入TIMED_WAITING状态,不出让锁

4、LockSupport中的park() 和 unpark()

总结一下,LockSupport比Object的wait/notify有两大优势:

  • LockSupport不需要在同步代码块里 。所以线程间也不需要维护一个共享的同步对象了,实现了线程间的解耦。说明:park和wait的区别。wait让线程阻塞前,必须通过synchronized获取同步锁。
  • unpark函数可以先于park调用,所以不需要担心线程间的执行的先后顺序。
  • park, 进入WAITING状态,对比wait不需要获得锁就可以让线程WAITING,通过unpark唤醒

5. join

等待该线程终止。

  • 等待调用join方法的线程结束,再继续执行。
  • 如:t.join();//主要用于等待t线程运行结束,若无此句,main则会执行完毕,导致结果不可预测。

yield() 与 wait()的比较

我们知道 ,wait() 的作用是让当前线程由“运行状态”进入“等待(阻塞)状态”的同时,也会释放同步锁 。而yield()的作用是让步,它也会让当前线程离开“运行状态”。它们的区别是:

  • (1) wait() 是让线程由“运行状态”进入到“等待(阻塞)状态”,而不yield()是让线程由“运行状态”进入到“就绪状态”。.
  • (2) wait()是会线程释放它所持有对象的同步锁,而yield()方法不会释放锁

sleep() 与 wait()的比较:

  • 我们知道,wait()的作用是让当前线程由“运行状态”进入“等待(阻塞)状态”的同时,也会释放同步锁。而sleep()的作用是也是让当前线程由“运行状态”进入到“休眠(阻塞)状态”。
  • 但是,wait()会释放对象的同步锁,而sleep()则不会释放锁。(sleep 不释放锁的原因,是因为 sleep 中可以传入睡眠时间,时间一到就将该线程加入到就绪队列中,因此不能释放锁,释放锁后重新获得锁的时间不可控)

sleep()与yield()的比较:

sleep和yield的区别在于, sleep可以使优先级低的线程得到执行的机会, 而yield只能使同优先级的线程有执行的机会.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值