park/unpark 阻塞与唤醒线程
使用 JAVA 进行多道编程时,除了通过 wait/notify 对线程进行阻塞/唤醒外,我们还可以使用 LockSupport 工具类来阻塞和唤醒线程。
比如:
Thread threadTest = new Thread( () -> { System.out.println("thread start!"); LockSupport.park(); System.out.println("thread weakup!"); } ); threadTest.start(); Thread.sleep(100); System.out.println(" from main thread"); LockSupport.unpark(threadTest);
执行结果:
与 wait/notify 相比,park/unpark 方法更贴近操作系统层面的阻塞与唤醒线程。park/unpark 没有基于对象锁的上层判断逻辑,更直接的通过系统调用来操作线程,当然在系统调用之上还是做了一些小封装。与 wait/notify 相比:
park
不需要获取某个对象的锁- 因为中断的时候
park
不会抛出InterruptedException
异常,所以需要在park
之后自行判断中断状态,然后做额外的处理。就像 sleep ,notify 唤醒后,jvm 会帮助我们检查一次是否有 interrupt 信号,其原理之前做过解析 https://www.cnblogs.com/niuyourou/p/12392942.html ,将检查 interrupt 信号的逻辑放在阻塞线程的逻辑之后,一旦被唤醒,首先执行检查 interrupt 信号的逻辑,检查完后退出 sleep/wait 方法,程序继续向下执行。而 park / unpark 并没有提供类似的机制,如果需要我们应自己在 park 方法后加入检查 interrupt 信号的逻辑。 - 想想happen-before原则中有一条,同一个锁的unlock操作happen-before此锁的lock操作。park/unpark 并没有涉及到锁操作,但我们确实有保证在一对操作中, park 发生在 unpark 之前的需求,否则可能会造成程序的死锁。关于这点 park/unpark 通过为线程附加状态位满足了我们的需求:unpark调用时,如果当前线程还未进入park,则将许可设置为true;park调用时,判断许可是否为true,如果是true,则 park 不阻塞线程,程序继续往下执行;如果是false,则阻塞线程。所以只要我们的 park/unpark 成对出现,无论执行顺序如何,都不会因此造成死锁。
当你看清人们的真相,于是你知道了,你可以忍受孤独