LockSupport 是什么?
解决了线程等待唤醒机制(wait/notify)
核心方法:
LockSupport 中的 park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程
线程唤醒和等待的方法
三种让线程等待和唤醒的方法
方式1: 使用 Object 中的 wait() 方法让线程等待,使用 Object 中的 notify() 方法唤醒线程。
方式2: 使用 JUC 包中 Condition 的 await() 方法让线程等待,使用 signal() 方法唤醒线程。
方式3: LockSupport 类可以阻塞当前线程以及唤醒指定被阻塞的线程。
方式1: Object 类中的 wait 和 notify 方法实现线程等待和唤醒
试验代码:
public class LockSupportDemo { static Object objectLock = new Object(); public static void main(String[] args) { // 1、wait、notify 需要配合 synchronized 使用 new Thread(() -> { // 2、唤醒线程只能唤醒当前 wait 的线程 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (objectLock) { System.out.println(Thread.currentThread().getName() + "\t =======> 进入锁"); try { objectLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "\t =======> 被唤醒"); } }, "A").start(); new Thread(() -> { synchronized (objectLock) { objectLock.notify(); System.out.println(Thread.currentThread().getName() + "\t =======> 发起通知"); } }, "B").start(); } }
总结:
1、wait、notify 需要配合 synchronized 使用不然会抛出异常
结论:Object 类中的 wait、notify 、notifyAll 用与线程等待和唤醒的方法,都必须要在 synchronized 内部执行(必须要使用 synchronized 关键在)
2、需要先阻塞后唤醒
/** * 要求:t1 线程等待 3 秒,3 秒后, t2 线程唤醒 t1 线程继续工作 * * 将 notify 放在 wait 方法之前执行,t1 先 notify 了, 3 秒钟后 t2 线程再执行 wait 方法 * 现象: * 程序一直无法结束 * 结论: * 先 wait 后 notify 、notifyAll方法、等待中的线程才会被唤醒,否则无法被唤醒 */ public class LockSupportDemo { static Object objectLock = new Object(); public static void main(String[] args) { new Thread(() -> { // 2、唤醒线程只能唤醒当前 wait 的线程 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (objectLock) { System.out.println(Thread.currentThread().getName() + "\t =======> 进入锁"); try { objectLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "\t =======> 被唤醒"); } }, "A").start(); new Thread(() -> { synchronized (objectLock) { objectLock.notify(); System.out.println(Thread.currentThread().getName() + "\t =======> 发起通知"); } }, "B").start(); } }
方式2: Condition 接口中的 await 后 singnal 方法实现线程的等待和唤醒
试验代码:
public class LockSupportConditionDemo { static Lock lock = new ReentrantLock(); static Condition condition = lock.newCondition(); public static void main(String[] args) { new Thread(() -> { lock.lock(); try { System.out.println(Thread.currentThread().getName() + "\t ====== 进入锁"); 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(); } }
结论:
1、condition 需要配合 Lock 一起使用。
2、需要先阻塞后唤醒
注:方式3 后续单独说明
传统的 synchronized 和 Lock 实现等待唤醒通知的约束
1、线程需要先获得并且持有锁,必须在锁块(synchronized 或 lock)中
2、必须要先等待后唤醒,线程才能够被唤醒