JUC并发编程之等待唤醒机制

简介: 在JUC(Java Util Concurrent)并发编程中,线程等待唤醒机制是实现线程之间协作和同步的重要手段。这种机制允许一个线程挂起等待某个条件满足后被唤醒,以及另一个线程在满足某个条件后唤醒等待的线程。在Java中,有多种实现线程等待唤醒机制的方式,包括使用Object的wait()和notify()方法、Condition接口以及LockSupport类。

1. 线程等待唤醒机制


在JUC(Java Util Concurrent)并发编程中,线程等待唤醒机制是实现线程之间协作和同步的重要手段。这种机制允许一个线程挂起等待某个条件满足后被唤醒,以及另一个线程在满足某个条件后唤醒等待的线程。在Java中,有多种实现线程等待唤醒机制的方式,包括使用Object的wait()和notify()方法、Condition接口以及LockSupport类。


1.1 使用Object的wait()和notify()方法


Object类是Java中所有类的父类,在多线程编程中,我们可以利用Object的wait()和notify()方法实现线程等待唤醒机制。这种方式需要在同步代码块中进行操作,因为wait()和notify()方法必须在同步块中调用。

public class WaitNotifyExample {
    public static void main(String[] args) {
        final Object lock = new Object();
        Thread waitingThread = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Waiting thread: Started waiting...");
                try {
                    lock.wait(); // 线程等待,释放锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Waiting thread: Resumed!");
            }
        });
        Thread notifyingThread = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Notifying thread: Started notifying...");
                lock.notify(); // 唤醒等待线程
                System.out.println("Notifying thread: Finished notifying");
            }
        });
        waitingThread.start();
        try {
            Thread.sleep(1000); // 确保等待线程先执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        notifyingThread.start();
    }
}


在上面的示例中,我们创建了两个线程:waitingThread和notifyingThread。waitingThread首先获取锁并调用lock.wait(),进入等待状态,并释放了锁。接着,notifyingThread获取锁,调用lock.notify()唤醒了等待线程。注意,wait()和notify()方法都必须在synchronized块内部使用,否则会抛出IllegalMonitorStateException。


1.2 使用Condition接口


Condition接口是Java并发包(java.util.concurrent.locks)中的一部分,它提供了类似于Object的wait()和notify()方法的功能,但更加灵活。可以在一个Lock对象上通过Condition来实现线程的等待和唤醒。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionExample {
    public static void main(String[] args) {
        final Lock lock = new ReentrantLock();
        final Condition condition = lock.newCondition();
        Thread waitingThread = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Waiting thread: Started waiting...");
                condition.await(); // 线程等待
                System.out.println("Waiting thread: Resumed!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });
        Thread notifyingThread = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Notifying thread: Started notifying...");
                condition.signal(); // 唤醒等待线程
                System.out.println("Notifying thread: Finished notifying");
            } finally {
                lock.unlock();
            }
        });
        waitingThread.start();
        try {
            Thread.sleep(1000); // 确保等待线程先执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        notifyingThread.start();
    }
}


在上述示例中,我们使用了ReentrantLock作为锁,通过调用lock.newCondition()创建了一个与该锁关联的Condition实例。然后,等待线程在等待前调用condition.await()进行等待,而唤醒线程通过condition.signal()来唤醒等待的线程。


1.3 使用LockSupport类


LockSupport类是Java并发包(java.util.concurrent.locks)中的工具类,它提供了一种基于线程的阻塞和唤醒机制,不需要依赖于特定的对象实例。


LockSupport的实现依赖于每个线程持有的一个许可(permit)。线程调用park()方法时,如果它持有许可,则立即返回;否则,将会阻塞(挂起)。线程调用unpark(Thread thread)方法时,如果线程处于挂起状态且持有许可,则会使其恢复运行。如果线程尚未调用park()方法或之前已经调用过unpark()方法,并且还持有许可,则后续的park()调用将不会阻塞。而Object类实现线程等待唤醒机制中先notify再wait就会一直处于阻塞状态,Condition接口同理。


LockSupport使用了类似信号量的机制,只有一个许可可供线程使用。如果一个线程调用了unpark(Thread thread)方法,而目标线程还没有调用park()方法,那么目标线程在之后调用park()方法时将立即返回,而不会阻塞。


在内部实现上,LockSupport使用了一些底层的Java本地接口(JNI)来实现线程的挂起和恢复。它通过修改线程的内部状态来达到挂起和恢复线程的目的。


import java.util.concurrent.locks.LockSupport;
public class LockSupportExample {
    public static void main(String[] args) {
        Thread waitingThread = new Thread(() -> {
            System.out.println("Waiting thread: Started waiting...");
            LockSupport.park(); // 线程挂起
            System.out.println("Waiting thread: Resumed!");
        });
        Thread notifyingThread = new Thread(() -> {
            System.out.println("Notifying thread: Started notifying...");
            LockSupport.unpark(waitingThread); // 唤醒线程
            System.out.println("Notifying thread: Finished notifying");
        });
        waitingThread.start();
        try {
            Thread.sleep(1000); // 确保等待线程先执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        notifyingThread.start();
    }
}


相关文章
|
11月前
|
人工智能 安全 中间件
阿里云 AI 中间件重磅发布,打通 AI 应用落地“最后一公里”
9 月 26 日,2025 云栖大会 AI 中间件:AI 时代的中间件技术演进与创新实践论坛上,阿里云智能集团资深技术专家林清山发表主题演讲《未来已来:下一代 AI 中间件重磅发布,解锁 AI 应用架构新范式》,重磅发布阿里云 AI 中间件,提供面向分布式多 Agent 架构的基座,包括:AgentScope-Java(兼容 Spring AI Alibaba 生态),AI MQ(基于Apache RocketMQ 的 AI 能力升级),AI 网关 Higress,AI 注册与配置中心 Nacos,以及覆盖模型与算力的 AI 可观测体系。
1821 85
|
9月前
|
人工智能 运维 供应链
20个低代码开发平台多维度对比:解锁企业应用开发新动能
Gartner 报告指出,到 2024 年,低代码应用开发将占应用开发总数的 65%以上,将有 3/4 的大型企业会使用至少 4 个低代码平台进行 IT 应用开发。同时,市场研究机构的数据显示,在传统开发模式下,超过 70% 的企业项目存在开发周期延长的问题,平均延长时间达到原计划的 30%;约 80% 的企业表示在招募专业开发人才时面临困难;而面对个性化需求,近 90% 的企业认为传统开发响应速度慢,无法及时满足业务变化需求。这些数据充分表明,当前企业在应用开发上面临问题具有普遍性和严重性,低代码开发平台的兴起势在必行 ,其有望成为解决这些难题、推动企业数字化转型的关键力量。
974 0
|
消息中间件 存储 人工智能
Apache RocketMQ for AI 战略升级,开启 AI MQ 新时代
Apache RocketMQ 顺应AIGC浪潮,针对长时会话、稀缺算力调度及AI Agent协作等挑战,推出专为AI时代打造的消息引擎。通过“会话即主题”的Lite-Topic机制,实现百万级队列动态管理,保障会话连续性与断点续传;结合智能资源调度能力,如定速消费与优先级队列,提升算力利用率与服务公平性;同时构建高效异步通信枢纽,支撑Agent-to-Agent及AI工作流的非阻塞协同。已在阿里集团与阿里云多个AI产品中大规模验证,助力开发者构建稳定、高效、可扩展的AI应用基础设施。
|
10月前
|
存储 缓存 算法
深入理解JVM《JVM内存区域详解 - 世界的基石》
Java代码从编译到执行需经javac编译为.class字节码,再由JVM加载运行。JVM内存分为线程私有(程序计数器、虚拟机栈、本地方法栈)和线程共享(堆、方法区)区域,其中堆是GC主战场,方法区在JDK 8+演变为使用本地内存的元空间,直接内存则用于提升NIO性能,但可能引发OOM。
|
存储 缓存 数据库
缓存技术有哪些应用场景呢
【10月更文挑战第19天】缓存技术有哪些应用场景呢
|
存储 NoSQL Java
Spring Session框架
Spring Session 是一个用于在分布式环境中管理会话的框架,旨在解决传统基于 Servlet 容器的会话管理在集群和云环境中的局限性。它通过将用户会话数据存储在外部介质(如数据库或 Redis)中,实现了会话数据的跨服务器共享,提高了应用的可扩展性和性能。Spring Session 提供了无缝集成 Spring 框架的 API,支持会话过期策略、并发控制等功能,使开发者能够轻松实现高可用的会话管理。
399 0
Spring Session框架
|
存储 Java BI
Java基础之stream流最新版,stream流的基本操作
Java基础之stream流最新版,stream流的基本操作
446 0
|
消息中间件 监控 Java
好文!12个策略解决 Kafka 数据丢失问题
以上这些策略对于解决 kafka 数据丢失问题很有帮助,如果你正在使用 kafka,或者正在学习 kafka,V 哥觉得你都应该把这12种策略收藏起来并消化掉,这对你在大型项目应用中非常有用。欢迎关注威哥爱编程,一起向技术大神进发。
1102 0
|
算法 Java 程序员
抢红包必看!算法决定你的红包大小
嗨,大家好!我是小米,热爱分享的技术程序员。今天聊聊红包算法——在保证公平、随机与乐趣的同时,如何巧妙分配红包金额。主要分为线性切割法与二倍均值法。前者通过随机切割区间,后者则确保金额在一定范围内随机,使分配更均匀。两种方法各有千秋,适用于不同场合,希望能给你带来灵感!
1100 0
|
存储 消息中间件 Java
新一代消息中间件—Apache Pulsar
新一代消息中间件—Apache Pulsar
1961 0
新一代消息中间件—Apache Pulsar