企业网站在ps里做吗wordpress 点击文章图片
news/
2025/9/30 20:27:07/
文章来源:
企业网站在ps里做吗,wordpress 点击文章图片,工装效果图网站,做网站的类型第1章#xff1a;引言
大家好#xff0c;我是小黑#xff0c;今天咱们要聊聊Lock Support。Lock Support是Java并发编程的一块基石#xff0c;它提供了一种非常底层的线程阻塞和唤醒机制#xff0c;是许多高级同步工具的基础。
为什么要关注Lock Support#xff1f;线程… 第1章引言
大家好我是小黑今天咱们要聊聊Lock Support。Lock Support是Java并发编程的一块基石它提供了一种非常底层的线程阻塞和唤醒机制是许多高级同步工具的基础。
为什么要关注Lock Support线程是并发执行的基本单元。咱们经常会遇到需要控制线程执行顺序的情况比如防止资源冲突、确保数据一致性。这时候就需要一些同步机制来拯救局面。Lock Support提供了一种灵活的线程阻塞和唤醒方式不同于传统的synchronized和ReentrantLock它更加轻量更容易融入各种并发场景。
第2章Lock Support简介
Lock Support听起来是不是有点像是某个高大上的技术其实它就是Java.util.concurrent包里的一个工具类。这个类里最重要的就是两个方法park() 和 unpark()。这两个小伙伴一个负责让线程停下来另一个负责让线程继续跑。听起来很简单对吧但它们可是大有来头。
在Java里锁和同步是常见的话题。传统的同步工具像synchronized和ReentrantLock都是阻塞式的意味着当一个线程获取不到锁时就会进入阻塞状态等待唤醒。这种方式虽然简单但有时候效率不高尤其是在高并发场景下。这时Lock Support就闪亮登场了。
举个例子假设小黑现在正在写一个并发程序需要控制线程A和线程B的执行顺序。小黑可以用Lock Support轻松实现
public class LockSupportExample {public static void main(String[] args) {final Thread threadA new Thread(() - {System.out.println(线程A等待信号);LockSupport.park(); // 线程A停下来等待System.out.println(线程A收到信号);});final Thread threadB new Thread(() - {System.out.println(线程B发送信号);LockSupport.unpark(threadA); // 唤醒线程A});threadA.start();threadB.start();}
}这段代码中线程A会在调用park()时停下来直到线程B调用unpark(threadA)线程A才会继续执行。这就是Lock Support的魅力所在简单而强大。
第3章基本概念和原理
Lock Support的核心就是两个方法park() 和 unpark()。park() 用来阻塞当前线程unpark(Thread thread) 则用来唤醒指定的线程。这听起来很像操作系统中的挂起和继续执行的概念但Lock Support比这更灵活。
park() 并不是传统意义上的锁。它不会去竞争什么资源只是纯粹地阻塞线程。而且它还有一个非常酷的特性——不易产生死锁。因为park() 在等待过程中如果接收到了unpark()的信号它会立刻返回这就避免了像synchronized 那样容易陷入死锁的问题。
再来看看unpark()。这个方法的作用是取消对指定线程的阻塞。有趣的是unpark() 可以在park() 之前调用。这就意味着如果线程A已经提前被unpark()了那么当它后续执行park()时它会感知到这个信号并且不会真的进入阻塞状态。
import java.util.concurrent.locks.LockSupport;public class ProducerConsumerExample {private static Thread consumerThread;private static Thread producerThread;public static void main(String[] args) {Object data null; // 用于存储生产的数据consumerThread new Thread(() - {System.out.println(消费者等待数据...);LockSupport.park(); // 消费者线程等待System.out.println(消费者收到数据: data);});producerThread new Thread(() - {data produceData(); // 生产数据System.out.println(生产者生产了数据: data);LockSupport.unpark(consumerThread); // 唤醒消费者线程});consumerThread.start();producerThread.start();}private static Object produceData() {// 模拟数据生产过程return Java数据;}
}在这段代码里消费者线程首先启动并调用park()等待数据。生产者线程生产数据后调用unpark(consumerThread)来唤醒消费者线程。注意这里的park() 和 unpark() 是如何配合的它们之间没有明显的锁竞争却能有效地协调线程间的活动。
Lock Support的工作原理相当于是给线程发放“许可证”。当调用park()时如果已经有许可证了它会立刻消费这个许可证并返回如果没有许可证线程就会阻塞。当调用unpark()时就是在给线程发放一个许可证。但有趣的是这个许可证是不可累积的无论调用多少次unpark()每个线程最多只能持有一个许可证。
这种机制的好处是显而易见的。它比起传统的锁操作更加轻量更少的锁竞争也就意味着更高的效率和更低的死锁风险。而且Lock Support的设计也非常巧妙它允许unpark()在park()之前调用这给很多并发控制场景提供了更多的灵活性。
使用Lock Support也需要注意一些问题。比如线程在调用park()后可能因为中断而返回但这并不会抛出InterruptedException异常。这就意味着当线程在等待时被中断它可能会在没有接收到期望的信号的情况下继续执行。因此编写依赖于Lock Support的代码时需要特别留意线程的中断状态。
第4章Lock Support与线程状态的交互
Lock Support与线程状态
当线程调用LockSupport.park()时它会进入WAITING状态。在这种状态下线程是被动的不会占用任何CPU资源就好像是在说“我没事干了别管我直到有人叫醒我。” 这种机制对于实现一些等待/通知的并发模式特别有用因为它减少了资源的消耗。
而当另一个线程调用LockSupport.unpark(目标线程)时原本在等待的线程会返回到RUNNABLE状态准备继续执行。这就好比是有人拍拍它说“嘿起床时间到了该干活了。”
代码示例线程状态变化
让我们通过一个例子来具体看看这是怎么回事。假设小黑想监控一个线程的状态变化。
public class ThreadStateExample {public static void main(String[] args) throws InterruptedException {Thread monitorThread new Thread(() - {System.out.println(监控线程运行中...);LockSupport.park(); // 让监控线程进入WAITING状态System.out.println(监控线程被唤醒继续运行);});monitorThread.start();Thread.sleep(1000); // 稍微等一会儿System.out.println(监控线程的状态: monitorThread.getState()); // 打印监控线程的状态LockSupport.unpark(monitorThread); // 唤醒监控线程Thread.sleep(100); // 再等一小会儿System.out.println(监控线程的状态: monitorThread.getState()); // 再次打印监控线程的状态}
}在这个例子中监控线程开始时处于RUNNABLE状态。当它调用LockSupport.park()后它就进入了WAITING状态。这时如果我们打印这个线程的状态就会看到它是WAITING。然后当主线程调用LockSupport.unpark(monitorThread)后监控线程被唤醒回到了RUNNABLE状态。
这个例子展示了线程如何在不同状态之间转换尤其是WAITING和RUNNABLE之间的转换。这种转换是非常重要的因为它让我们可以有效地管理线程使其在需要的时候等待不需要的时候又能迅速恢复运行。
第5章Lock Support在实际应用中的案例分析
案例1自定义的阻塞队列
首个案例是自定义一个阻塞队列。在并发编程中阻塞队列是一个常见的数据结构用于在生产者和消费者之间传递数据。让我们看看如何使用Lock Support来实现一个简单的阻塞队列。
import java.util.concurrent.locks.LockSupport;public class CustomBlockingQueueT {private NodeT head, tail;private int size 0;private final int capacity;private Thread enqThread, deqThread;public CustomBlockingQueue(int capacity) {this.capacity capacity;head tail new Node(null);}public void enqueue(T item) {if (size capacity) {enqThread Thread.currentThread();LockSupport.park(); // 队列满时阻塞生产者线程}tail tail.next new Node(item);size;if (deqThread ! null) {LockSupport.unpark(deqThread); // 唤醒消费者线程deqThread null;}}public T dequeue() {if (size 0) {deqThread Thread.currentThread();LockSupport.park(); // 队列空时阻塞消费者线程}T item head.next.item;head head.next;size--;if (enqThread ! null) {LockSupport.unpark(enqThread); // 唤醒生产者线程enqThread null;}return item;}static class NodeT {T item;NodeT next;Node(T item) {this.item item;}}
}这个阻塞队列中当生产者发现队列已满时会调用LockSupport.park()来阻塞自己直到有空间可用。同理消费者在队列为空时会被阻塞。这是Lock Support在控制线程状态上的一个典型应用。
案例2简单的同步锁
下面是一个使用Lock Support实现的简单同步锁。这个锁在设计时考虑到了公平性即按照线程请求锁的顺序来分配锁。
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;public class FairLock {private final QueueThread waiters new ConcurrentLinkedQueue();private final AtomicBoolean locked new AtomicBoolean(false);public void lock() {Thread current Thread.currentThread();waiters.add(current);// 只有队列首个元素能获取锁while (waiters.peek() ! current || !locked.compareAndSet(false, true)) {LockSupport.park();}waiters.remove();}public void unlock() {locked.set(false);LockSupport.unpark(waiters.peek()); // 唤醒下一个等待线程}
}在这个锁的实现中如果当前线程不是队列中的第一个或者锁已被其他线程占用它就会调用LockSupport.park()来阻塞自己。当锁被释放时会唤醒队列中的下一个线程。
第6章Lock Support与Java并发工具的集成
结合ReentrantLock和Lock Support
让我们先来看一个结合ReentrantLock和Lock Support的例子。假设小黑要实现一个同步机制在这个机制中我们想让线程在等待ReentrantLock的锁释放时能够做一些额外的工作。
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;public class EnhancedReentrantLock extends ReentrantLock {private Thread leader null;Overridepublic void lock() {boolean wasInterrupted false;while (true) {if (tryAcquire(1)) {if (wasInterrupted) {// 如果之前被中断过恢复中断状态Thread.currentThread().interrupt();}return;}// 如果已有线程在排队则阻塞当前线程if (hasQueuedPredecessors() leader null) {leader Thread.currentThread();LockSupport.park(this);leader null;if (Thread.interrupted()) { // 如果park返回是因为中断wasInterrupted true;}}}}
}在这个例子中小黑扩展了ReentrantLock添加了一些Lock Support的功能。当有线程在等待锁时它会通过Lock Support被阻塞。这样做的好处是可以更灵活地控制线程的等待状态比如在等待过程中做一些额外的检查或者处理。
结合Semaphore和Lock Support
现在让我们看一个结合Semaphore信号量和Lock Support的例子。信号量是另一种常见的并发控制工具用于限制对资源的访问。
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.Semaphore;public class CustomSemaphore {private final Semaphore semaphore;private volatile Thread blocker null;public CustomSemaphore(int permits) {this.semaphore new Semaphore(permits);}public void acquire() throws InterruptedException {blocker Thread.currentThread();semaphore.acquire();blocker null;}public void release() {semaphore.release();LockSupport.unpark(blocker); // 唤醒阻塞的线程}
}在这个例子中小黑创建了一个自定义的信号量它在内部使用了Semaphore但是在获取和释放许可的同时还运用了Lock Support来控制线程的阻塞和唤醒。这样的组合增加了控制的灵活性可以在更复杂的场景下使用。
第7章性能考量和最佳实践
Lock Support的性能特性
Lock Support的性能主要体现在它提供的park()和unpark()操作上。这两个操作相比于Object.wait()和notify()来说更加轻量级因为它们不需要进入同步区。这就意味着Lock Support在高并发环境下能更好地减少线程的上下文切换提高系统的整体性能。
但是这并不意味着Lock Support总是性能最优的选择。例如在一些特定场景下使用重量级锁如ReentrantLock可能会更有效尤其是当锁竞争不是非常激烈或者需要更复杂的锁功能时。
Lock Support的最佳实践
现在让我们来看几个关于使用Lock Support的最佳实践 正确处理中断当线程在park()时被中断它会返回但不会抛出InterruptedException。因此我们需要检查线程的中断状态并相应地处理它。 public void parkAndCheckInterrupt() {LockSupport.park();if (Thread.interrupted()) {// 处理中断逻辑System.out.println(线程被中断了);}
}避免虚假唤醒因为park()可能会无故返回虚假唤醒最好在一个循环中调用它检查某个条件是否满足。 while (!conditionMet()) {LockSupport.park();
}合理使用unpark()由于unpark()可以在park()之前调用因此我们可以利用这一点来避免不必要的阻塞。 public void sendData(Object data) {// 先设置数据this.data data;// 然后唤醒消费者线程LockSupport.unpark(consumerThread);
}不要过度依赖Lock Support虽然Lock Support是一个强大的工具但并不意味着它总是最佳的解决方案。在选择使用Lock Support之前应该考虑问题的具体情况评估是否有更适合的工具或方法。
第8章总结 基本概念Lock Support是一个提供线程阻塞和唤醒功能的工具类核心方法是park()和unpark()。这两个方法提供了一种比传统synchronized和ReentrantLock更轻量级的线程同步方式。 与线程状态的交互park()会使线程进入等待状态而unpark()则被用来唤醒线程。这种机制使得线程的管理更加灵活有助于提高并发程序的性能。 在实际应用中的案例我们看到了Lock Support在自定义阻塞队列、同步锁等场景的应用展示了其在复杂并发控制中的实用性。 与其他并发工具的结合Lock Support可以与Java中的其他并发工具如ReentrantLock, Semaphore等结合使用为解决复杂的并发问题提供更多可能性。 性能考量和最佳实践虽然Lock Support是轻量级的但在使用时仍需注意其特性比如正确处理中断、避免虚假唤醒等以确保并发程序的稳定性和效率。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/923226.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!