Java并发编程:LockSupport深度解析与应用

1 下载量 130 浏览量 更新于2024-08-03 收藏 345KB PDF 举报
"Java 多线程与并发(9/26)-JUC锁: LockSupport详解" 在Java并发编程中,LockSupport是Java Util Concurrency (JUC)包下非常重要的一个工具类,它是构建高级同步构造如ReentrantLock、Semaphore等的基础。LockSupport主要提供了`park()`和`unpark()`两个方法,用于线程的阻塞和唤醒,从而实现线程间的协作。这两个方法比传统的`wait()`和`notify()`更为灵活,因为它们并不依赖于对象的监视器(monitor)。 ### 1. 为什么LockSupport也是核心基础类? LockSupport之所以重要,是因为它和Unsafe一起,为Java的并发库提供了底层支持。Unsafe提供了原子操作(如CAS),而LockSupport则提供了线程阻塞和解除阻塞的机制。这两个工具的结合使得开发者可以构建出高效且线程安全的并发组件。 ### 2. wait/notify与park/unpark的区别 - `wait()/notify()`是基于对象监视器的,需要在同步块或同步方法中使用,而`park()/unpark()`不依赖于任何特定的同步上下文。 - `wait()`会释放锁资源,`park()`不会释放锁,除非被中断或者收到`unpark()`指令。 - `notify()`随机唤醒一个等待的线程,而`unpark()`明确地使指定的线程继续执行。 ### 3. park()与Condition.await() - `park()`仅仅让当前线程等待,不会释放锁,而`Condition.await()`在等待前会释放关联的锁资源,然后等待被唤醒。 - `Condition.await()`需要与`Condition.signal()`或`Condition.signalAll()`配合使用,而`park()`与`unpark()`配对使用。 ### 4. Thread.sleep(), Object.wait(), Condition.await(), LockSupport.park()的区别 - `Thread.sleep()`使线程休眠指定的时间,不会释放任何锁资源,醒来后仍需竞争锁。 - `Object.wait()`在同步块中使用,会释放锁并等待,被`notify()`或`notifyAll()`唤醒。 - `Condition.await()`在条件队列中等待,释放锁,被`signal()`或`signalAll()`唤醒。 - `LockSupport.park()`阻塞当前线程,但不释放锁,被`unpark()`唤醒。 ### 5. wait()前的notify()与park()前的unpark() - 在`wait()`之前执行`notify()`,可能会导致线程调度的不确定性,因为`wait()`后线程会被放入等待池,而此时已有的`notify()`可能无法保证唤醒等待池中的线程。 - 在`park()`之前执行`unpark()`,则`park()`的调用将立即返回,因为已经有一个许可可用。 ### 6. LockSupport源码分析 LockSupport的实现依赖于`sun.misc.Unsafe`,这是Java的非公开类,提供了对内存的直接访问和原子操作。`park()`和`unpark()`的实现利用了 Unsafe 的内存操作,以实现高效的线程阻塞和恢复。 ```java // 获取Unsafe实例 UNSAFE = sun.misc.Unsafe.getUnsafe(); ``` `parkBlockerOffset`, `SEED`, `PROBE`, 和 `SECONDARY` 是内存偏移量,用于内部实现细节,如线程阻塞原因的跟踪和无锁算法的优化。 LockSupport作为一个底层的线程控制工具,提供了更细粒度的线程阻塞和唤醒控制,使得开发者能够构建更复杂的并发模型,但它并不适合日常的简单同步需求,而是用于构建高级的并发组件。在理解和使用LockSupport时,必须谨慎,以避免死锁、饥饿等问题。