LockSupport
LockSupport提供的park/unpark是以线程的角度来设计,真正解耦了线程之间的同步。
核心方法
park()方法,对当前线程执行阻塞操作,直到获取到可用许可后才解除阻塞,也就相当于当前线程进入阻塞状态。
park 方法还可以在其他任何时间“毫无理由”地返回,因此通常必须在重新检查返回条件的循环里调用此方法。park不会释放当前线程占有的锁资源。
parkNanos(long)方法,对当前线程执行阻塞操作,等待获取到可用许可后才解除阻塞,最大的等待时间由传入的参数来指定,一旦超过最大时间它也会解除阻塞。
parkUntil(long)方法,,对当前线程执行阻塞操作,等待获取到可用许可后才解除阻塞,最大的等待时间为参数所指定的最后期限时间。
park(Object)方法,与park()方法同义,但它多传入的参数为阻塞对象。
parkNanos(Object,long)方法,与parkNanos(long)同义,但指定了阻塞对象。
parkUntil(Object,long)方法,与parkUntil(long)同义,但指定了阻塞对象。
unpark(Thread)方法,将指定线程的许可置为可用,也就相当于唤醒了该线程。
许可机制
对于LockSupport使用的许可可看成是一种二元信号,该信号分有许可和无许可两种状态。每个线程都对应一个信号变量,当线程调用park时其实就是去获取许可,如果能成功获取到许可则能够往下执行,否则则阻塞直到成功获取许可为止。而当线程调用unpark时则是释放许可,供线程去获取。park/unpark方式的执行顺序不影响唤醒,不会造成死锁。
park 对立中断的响应
park方法支持中断,也就是说一个线程调用park方法进入阻塞后,如果该线程被中断则能够解除阻塞立即返回。但需要注意的是,它不会抛出中断异常,所以我们不必去捕获InterruptedException。
Thread.sleep()和LockSupport.park()的区别
- 从功能上来说,Thread.sleep()和LockSupport.park()方法类似,都是阻塞当前线程的执行,且都不会释放当前线程占有的锁资源;
- Thread.sleep()没法从外部唤醒,只能自己醒过来;LockSupport.park()方法可以被另一个线程调用LockSupport.unpark()方法唤醒;
- Thread.sleep()方法声明上抛出了InterruptedException中断异常,所以调用者需要捕获这个异常或者再抛出;LockSupport.park()方法不需要捕获中断异常;
Object.wait()和LockSupport.park()的区别
- Object.wait()方法需要在synchronized块中执行;LockSupport.park()可以在任意地方执行;
- Object.wait()方法声明抛出了中断异常,调用者需要捕获或者再抛出;LockSupport.park()不需要捕获中断异常;
- Object.wait()不带超时的,需要另一个线程执行notify()来唤醒,但不一定继续执行后续内容;LockSupport.park()不带超时的,需要另一个线程执行unpark()来唤醒,一定会继续执行后续内容;
- 如果在wait()之前执行了notify()会抛出IllegalMonitorStateException异常;
- 如果在park()之前执行了unpark()线程不会被阻塞,直接跳过park(),继续执行后续内容;