LockSuport
java.util.concurrent.locks.LockSuport
-
用于创建锁和其他同步类的基本线程阻塞原语。
这个类与每个使用它的线程相关联,一个许可证(在
Semaphore
类的意义上)。 如果许可证可用,则呼叫park
将park
返回,在此过程中消耗它; 否则可能会阻止。 致电unpark
使许可证可用,如果尚不可用。 (与信号量不同,许可证不能累积,最多只有一个。)方法
park
和unpark
提供了阻止和解除阻塞线程的有效手段,该方法不会遇到导致不推荐使用的方法Thread.suspend
和Thread.resume
目的不能使用的问题:一个线程调用park
和另一个线程之间的尝试unpark
线程将保持活跃性,由于许可证。 另外,如果调用者的线程被中断,park
将返回,并且支持超时版本。park
方法也可以在任何其他时间返回,因为“无理由”,因此一般必须在返回之前重新检查条件的循环中被调用。 在这个意义上,park
作为一个“忙碌等待”的优化,不浪费时间旋转,但必须与unpark
配对才能有效。park
的三种形式也支持blocker
对象参数。 线程被阻止时记录此对象,以允许监视和诊断工具识别线程被阻止的原因。 (此类工具可以使用方法getBlocker(Thread)
访问阻止程序 。)强烈鼓励使用这些形式而不是没有此参数的原始形式。 在锁实现中作为blocker
提供的正常参数是this
。这些方法被设计为用作创建更高级同步实用程序的工具,并且本身对于大多数并发控制应用程序本身并不有用。
park
方法仅用于形式的构造:while (!canProceed()) { ... LockSupport.park(this); }
canProceed
也没有任何其他动作之前的呼叫park
需要锁定或阻止。 因为只有一个许可证与每个线程相关联,park
任何中介使用可能会干扰其预期效果。
三种让线程等待和唤醒的方法:
1、使用 Object 中的 wait() 方法让线程等待,使用Object中的 notify() 方法唤醒线程;
public class LockSupperDemo { public static Object object = new Object(); public static void main(String[] args) { /** * 1、wait()和 notify()必须放在synchronized同步代码块中执行, * 否则会报错:java.lang.IllegalMonitorStateException * * 2、wait()和 notify()成对出现,并且必须先等待再唤醒,线程才能够被唤醒 */ new Thread(() -> { synchronized (object) { System.out.println(Thread.currentThread().getName() + "\t come in"); try { object.wait();//阻塞 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "\t 被唤醒"); } }, "A").start(); new Thread(() -> { synchronized (object) { object.notify();//唤醒 System.out.println(Thread.currentThread().getName() + "\t 唤醒动作"); } }, "B").start(); } }
2、使用 JUC 中的 Condition 的 await() 方法让线程等待,使用 signal() 方法唤醒线程;
public static Lock lock = new ReentrantLock(); public static Condition condition = lock.newCondition(); public static void main(String[] args){ /** * 1、await()和 signal()必须放在 lock 代码块中执行, * 否则会报错:java.lang.IllegalMonitorStateException * * 2、await()和 signal()必须先等待再唤醒,线程才能够被唤醒 */ new Thread(() ->{ lock.lock(); try { System.out.println(Thread.currentThread().getName() + "\t come in"); condition.await();//等待 System.out.println(Thread.currentThread().getName() + "\t 被唤醒"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } },"A").start(); new Thread(() -> { lock.lock(); try { condition.signal();//唤醒 System.out.println(Thread.currentThread().getName() + "\t 唤醒动作"); }finally { lock.unlock(); } }, "B").start(); }
3、使用 LockSupport 类可以阻塞当前线程以及唤醒指定被阻塞的线程;
static void |
park()
禁止当前线程进行线程调度,除非许可证可用。
|
static void |
park(Object blocker)
禁止当前线程进行线程调度,除非许可证可用。
|
static void |
LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit);
permit只有两个值 0和1,默认为0;
public static void main(String[] args){ /** * 1、不需要放在锁代码块中 * * 2、先唤醒后阻塞,线程照样执行 */ Thread a = new Thread(() ->{ System.out.println(Thread.currentThread().getName() + "\t come in"); LockSupport.park();//阻塞。。需要一个许可证 System.out.println(Thread.currentThread().getName() + "\t 被唤醒"); },"a"); a.start(); new Thread(() ->{ LockSupport.unpark(a);//给a线程发放许可证 System.out.println(Thread.currentThread().getName() + "\t 唤醒动作"); },"B").start(); }