当前位置:首页 > 技术 > 正文内容

Java线程状态与并发协作机制详解

访客 技术 2026年9月25日 13

线程的六种状态解析

在Java中,每个线程在其生命周期中会经历不同的状态。这些状态由java.lang.Thread.State枚举定义,共包括六种:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING 和 TERMINATED。

状态 触发条件
NEW 线程对象已创建,但尚未调用start()方法
RUNNABLE 线程正在JVM中运行,可能正在执行代码,也可能正等待CPU调度
BLOCKED 线程尝试获取一个被其他线程持有的监视器锁时进入此状态
WAITING 线程调用wait()、join()或LockSupport.park()后无限期等待其他线程唤醒
TIMED_WAITING 线程在指定时间内等待,如调用sleep(long)、wait(long)、join(long)等带超时参数的方法
TERMINATED 线程任务完成或因未捕获异常而终止

TIMED_WAITING 状态深入理解

当线程调用Thread.sleep(1000)时,它会进入计时等待状态,期间不参与CPU调度,也不会竞争锁资源。时间结束后自动恢复为RUNNABLE状态,但并不保证立即执行,仍需重新竞争处理器资源。

new Thread(() -> {
    try {
        System.out.println("线程开始休眠");
        Thread.sleep(2000); // 进入TIMED_WAITING
        System.out.println("线程苏醒");
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}).start();

BLOCKED 状态产生场景

多个线程竞争同一把同步锁时,若某一线程持有锁,则其余线程将处于BLOCKED状态,直到锁被释放并成功获取为止。

WAITING 与线程协作

WAITING状态体现的是线程间的协作关系。例如,一个线程调用对象的wait()方法后进入等待,必须由另一个线程在同一对象上调用notify()或notifyAll()才能将其唤醒。

线程间通信:等待唤醒机制

当多个线程操作共享资源且任务不同(如生产者-消费者模型),需要通过协调机制确保数据一致性和执行顺序。

核心方法说明

  • wait():释放当前对象锁,使线程进入WAITING状态,等待其他线程通知。
  • notify():随机唤醒一个在该对象上等待的线程。
  • notifyAll():唤醒所有在该对象上等待的线程。

这三个方法属于Object类,因此任何对象都可以作为锁进行调用。使用时必须满足以下条件:

  1. 必须在同步上下文中调用(即synchronized块或方法内);
  2. 调用者必须是对应对象的监视器持有者;
  3. 通常配合循环判断使用,防止虚假唤醒。

经典案例:生产者与消费者

以包子铺为例,生产者线程制作包子,消费者线程吃包子。两者共享"是否有包子"的状态变量。

public class BunShop {
    private boolean hasBun = false;

    public synchronized void makeBun() throws InterruptedException {
        while (hasBun) {
            this.wait(); // 包子存在,生产者等待
        }
        System.out.println("生产者:开始做包子");
        Thread.sleep(1000);
        hasBun = true;
        this.notifyAll(); // 唤醒消费者
    }

    public synchronized void eatBun() throws InterruptedException {
        while (!hasBun) {
            this.wait(); // 没有包子,消费者等待
        }
        System.out.println("消费者:吃掉包子");
        hasBun = false;
        this.notifyAll(); // 唤醒生产者
    }
}

注意使用while而非if判断条件,避免因多线程唤醒导致的状态不一致问题。

线程池:高效管理并发任务

频繁创建和销毁线程会造成系统资源浪费。线程池通过复用已有线程来提升性能和稳定性。

线程池的优势

  • 降低开销:减少线程创建/销毁次数;
  • 提高响应速度:任务到达即可执行,无需等待线程初始化;
  • 可控性增强:限制最大并发数,防止资源耗尽导致系统崩溃。

核心接口与实现

ExecutorService 是主要的线程池接口,常用创建方式来自工具类 Executors:

  • newFixedThreadPool(int nThreads):创建固定大小的线程池;
  • newCachedThreadPool():可缓存线程池,适合短期异步任务;
  • newSingleThreadExecutor():单线程池,保证顺序执行任务。

基本使用流程

  1. 创建线程池:
    ExecutorService pool = Executors.newFixedThreadPool(3);
  2. 提交任务:
    pool.submit(() -> System.out.println("执行任务")); // Runnable
    Future<String> result = pool.submit(() -> "返回结果"); // Callable
  3. 关闭线程池:
    pool.shutdown(); // 平滑关闭,不再接收新任务
    // 或 pool.shutdownNow(); 强制中断

调用shutdown()后,主线程不会立即结束,因为线程池中的线程仍在运行已提交的任务。只有所有任务完成后,JVM才会正常退出。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。