Java线程状态全解析:BLOCKED/WAITING到底啥区别?jstack定位并发问题
Java技术圈里有个很有意思的现象但凡面试十有八九会问到Java线程的状态但凡问到线程状态大多数人的回答就停在“六种状态背名字”这个层面。我做Java开发十几年面试别人的时候几乎每场都会追问一句“那你觉得WAITING和BLOCKED到底有什么区别”能把这句话答利索的候选人比例比我预想的低得多。这篇文章不打算把官方文档再抄一遍而是从实际调试、踩坑和面试答疑的经验出发把Java线程的几种状态掰开揉碎讲清楚每个状态背后到底发生了什么事。搞清楚这六个状态最直接的三个收益是面试能讲出层次感、写并发代码能预判线程会卡在哪、线上看jstack输出能快速定位锁竞争和死锁问题。1. 先从“状态机”说起为什么需要这6种状态1.1 进程和线程的关系决定了状态模型的根基聊线程状态之前得先把“线程是什么”这件事摆正。很多人背概念很熟说线程是进程内的执行单元、是CPU调度的基本单位但一旦落到状态模型上就对应不上了。操作系统在调度线程时需要一个清晰的数据结构来记录每个线程当前在干什么是在排队等着CPU还是正在执行还是因为某个资源没到位而暂停了。这就是“状态”的由来。Linux上每个线程对应一个task_structJava里的Thread对象则是对内核调度实体的一层封装。所以Java线程的状态不是为了面试造概念而是为了忠实反映“这个线程现在到底处于什么情况”。Java线程状态定义在java.lang.Thread.State这个枚举里一共六个NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。把这六个当成一条流水线来看新建、能跑、跑不了、主动等、限时等、结束。理解了这个本质再去看各种并发工具和线程池的源码会发现所有设计都在围绕这六个状态打转。1.2 六种状态一张表垫底先建立全局观状态含义典型进入方式退出方式NEW线程对象已创建但还没调用start()new Thread()调用start()RUNNABLE可运行状态真正是否执行由操作系统调度start()之后被唤醒之后被调度执行或转入其他状态BLOCKED阻塞在synchronized锁上等monitor lock进入synchronized代码块但锁被占用抢到锁WAITING无限期等待另一个线程的通知Object.wait()、join()、LockSupport.park()notify/notifyAll、unpark、被join的线程结束TIMED_WAITING有超时的等待sleep(ms)、wait(ms)、join(ms)、parkNanos超时或被唤醒TERMINATED线程执行完或异常退出run()方法返回无后续状态这张表是地基但面试只背这张表拿不到高分。真正的分水岭在于状态之间的流转时机、底层机制以及不同并发工具分别把线程推进到哪个状态。2. 状态流转才是重点什么时候在哪个状态2.1 NEW到RUNNABLE之间那道坎start()到底做了什么线程new出来之后处于NEW状态此时线程对象存在但底层操作系统线程还没有创建。不少新手以为new Thread()就立刻创建了系统级线程这个理解是错的。真正创建底层线程的动作发生在调用start()那一刻。这里有一个高频考点一个Thread对象只能调用一次start()第二次调用会抛IllegalStateException。有同学会想“线程跑完了我再start一次复用它”不行。从状态机的角度也很好理解TERMINATED是终态状态图里没有一条从终态回到NEW的边线程对象用完就废。调用start()之后线程进入RUNNABLE。这里特别提醒RUNNABLE不表示“正在执行”而是“可以被调度器执行”。JVM把操作系统的Ready和Running两个子状态合并成了RUNNABLE因为Java语言规范层面无法也不想去精确区分这两个子状态。面试官追问“RUNNABLE到底是不是在跑”时你能答出这一层效果会明显不一样。2.2 RUNNABLE的两种走向要么执行要么排队线程处于RUNNABLE后实际上会有两种子情况要么正在被某个CPU核执行要么在调度队列里等待被分配CPU。这两种子状态在Java里无法区分但排查问题时我们经常能看到一种诡异现象线程状态一直是RUNNABLECPU却不高任务是卡死的。这种“伪RUNNABLE”通常发生在自旋等待、无锁循环、或者某些框架内部的忙等待逻辑里。真正让线程从RUNNABLE变成BLOCKED的场景只有一个想进入synchronized保护的临界区但锁被别的线程持有。注意是synchronized而不是ReentrantLock。ReentrantLock内部基于AQS线程等着拿锁时状态是WAITING不是BLOCKED。这个区别极其重要可以说是面试和排查问题的分水岭。举个最常见的锁竞争例子两个线程同时执行一个synchronized方法线程A先拿到锁进去了线程B就会进入BLOCKED。BLOCKED状态下的线程不做任何事不消耗CPU纯粹在monitor的entrySet里排队等锁。如果A迟迟不释放锁B就一直是BLOCKED这也就是锁竞争导致线程卡顿的基本原理。2.3 WAITING和TIMED_WAITING主动让出CPU的三类APIWAITING和TIMED_WAITING的共同点是线程主动让出CPU等待某个条件成立。唯一的区别是有没有超时时间。进入WAITING的API有三个Object.wait()、无参的Thread.join()、LockSupport.park()。进入TIMED_WAITING的API包括Thread.sleep(ms)、Object.wait(ms)、Thread.join(ms)、LockSupport.parkNanos(ns)、LockSupport.parkUntil(deadline)。这里大家最容易混的是sleep和wait。sleep是Thread的静态方法语义是“我歇一会儿你们先跑”它不释放任何锁wait是Object的方法语义是“我松开这把锁等别人来通知我”它会释放锁。一个是睡眠一个是等待设计意图完全不同后面第4章会展开讲这个坑。还有一个高频场景是join()。它的本质是当前线程等调用join的那个线程跑完。看jstack输出时如果发现主线程处于WAITING线程栈往往就停在某个线程的join方法或者Object.wait上。这个现象在任务串行化编排时非常常见别一看到主线程WAITING就以为出事故了。3. 用代码和工具亲眼观察一次状态流转3.1 用getState()把6种状态各跑一遍说了这么多理论不如直接跑一遍。Thread.getState()是观察线程状态最直接的方法虽然它只是快照式的采样但用来学习验证完全够用。先说最简单的NEW和TERMINATED。一个new出来的线程在start之前getState()返回NEW等run()方法执行完之后getState()返回TERMINATED。这个几乎不用写代码看一眼就能明白。再看RUNNABLE和TIMED_WAITING的切换。写一个死循环空转的线程循环里啥也不干直接跑Thread t new Thread(() - { while (true) { // 空转模拟计算任务 } }); t.start(); System.out.println(t.getState()); // 大概率是RUNNABLE再把循环体换成Thread.sleep(100)此时线程的状态就变成TIMED_WAITING。很多同学会问sleep的精度到底准不准Windows和Linux上sleep的最小调度粒度不一样但对观察状态没有实质影响。我在实验里习惯把当前线程名打出来Thread t new Thread(() - { System.out.println(当前执行线程 Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }, demo-thread);线程名这个细节不要小看。给线程起一个语义明确的名字后面线上看jstack定位问题就靠它了。如果不命名所有线程都叫Thread-0、Thread-1排查时根本分不清谁是谁只能靠栈里的类名去猜。3.2 synchronized锁竞争实验亲眼看一次BLOCKED来一个经典的小实验主线程先拿到锁子线程再去抢同一把锁。public class BlockedDemo { private static final Object LOCK new Object(); public static void main(String[] args) throws Exception { Thread t new Thread(() - { synchronized (LOCK) { try { Thread.sleep(2000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }, holder-thread); t.start(); Thread.sleep(100); // 确保holder先拿到锁 Thread t2 new Thread(() - { synchronized (LOCK) { System.out.println(拿到了锁); } }, waiter-thread); t2.start(); Thread.sleep(100); System.out.println(t2状态 t2.getState()); // 大概率是BLOCKED } }运行之后t2的状态基本可以断定是BLOCKED因为holder-thread此时还抱着锁在sleep。这个实验的价值在于让你直观感受“多个线程竞争同一把锁”和“各跑各的线程互不相干”之间的差别。很多并发问题难排查是因为线程之间的交互看不见摸不着状态API至少给了我们一扇观察的窗口。如果觉得getState()粒度不够还可以考虑用JFRJava Flight Recorder抓取更细的调度事件但对日常验证getState()已经足够。3.3 用jstack抓一次线程快照看真实项目里的状态分布比起getState()的单点采样线上排查用得更频繁的是jstack。它能打印出JVM内所有线程的完整快照包括线程状态、锁信息、堆栈调用、是否持有monitor等。操作很简单jstack pid或者用jcmd pid Thread.print。看到输出后重点看三样东西线程名、线程状态、栈顶方法。比如waiter-thread #18 prio5 os_prio0 tid0x0000... nid0x... waiting for monitor entry (BLOCKED)输出里经常跟着“Waiting to re-lock in wait()”或者“waiting on 0x... (a java.lang.Object)”之类的提示。这些都在告诉你它卡在哪把锁上、在哪个对象上等待。配合前面说的线程命名规范五分钟内就能圈定问题线程的范围。我在实际排查中超过一半的线程异常都能靠“打jstack、看状态、定位栈顶方法”这条路解决所以这几个状态不是背来应付面试的它们是线上诊断的基本工具。4. 死锁、锁竞争和那些踩过的坑4.1 WAITING、TIMED_WAITING、BLOCKED三者对比别再傻傻分不清面试最高频的一个问题是WAITING和BLOCKED有什么区别我的回答一般分两层。第一层是根本机制不同BLOCKED是在等一把已经被别人持有的synchronized锁是被动的、被迫排队WAITING是在等一个“条件满足”比如别人notify、别人unpark、被join的线程结束是主动让出CPU去等。第二层是体现在jstack里的特征不同BLOCKED的线程栈上会显示“waiting for monitor entry”说明线程在monitor的entrySet里排队WAITING的线程则显示“in Object.wait()”或“parking”。比如java.lang.Thread.State: WAITING (parking)看到parking就知道它是用了LockSupport.park()通常是在等AQS条件变量。如果线程WAITING在Object.wait()上那等的是对方notify。TIMED_WAITING就简单了多了一个截止时间。无论是sleep还是带超时的wait时间一到就自动回到RUNNABLE。这里藏着第二个高频问题sleep期间被interrupt会怎样答案是抛InterruptedException同时清除中断标记。这也是为什么写sleep的catch块时习惯性补一句Thread.currentThread().interrupt()是有讲究的它把中断标记重新设上让外层代码能感知到中断发生过避免吞掉中断信号。4.2 经典坑一wait释放锁sleep不释放锁带新人的时候发现很多人写多线程代码容易把wait和sleep搞混。这里给一个简单记忆方式凡是挂到某个对象上的等待都会释放该对象的锁凡是线程自己睡都不会影响别人持有的锁。wait是挂在对象上的释放锁sleep是线程自己的行为不释放锁。所以经典面试题“sleep和wait有什么区别”答案浓缩成两句话第一wait是Object的方法sleep是Thread的静态方法第二wait释放锁sleep不释放锁。顺带再说一句wait必须放在synchronized代码块里否则抛IllegalMonitorStateExceptionsleep没有这个限制。提示wait()和sleep()的根本区别在于锁的释放语义这个点面试出现的频率极高务必把“wait释放锁、sleep不释放锁”这句话刻在脑子里。还有一个坑藏在notify的选择上notify只唤醒一个等待线程如果此时有多个线程等在同一个对象上只有一个能被唤醒唤醒哪个由JVM决定不保证公平。除非你能确定只有一个线程在等否则用notifyAll更稳妥。这个坑在消费者场景里特别容易踩notify唤醒的恰好是不该干活的线程结果任务一直卡着没人处理。4.3 经典坑二线程池里的线程状态没那么好猜很多人以为线程池里的线程会规规矩矩地“运行、等待、再运行”实际上ThreadPoolExecutor里空闲线程的状态是TIMED_WAITING。因为默认的keepAlive实现是让工作线程在getTask()里执行workQueue.poll(keepAliveTime, TimeUnit.SECONDS)这个带超时的poll会让线程进入TIMED_WAITING。所以观察线程池状态时看到一堆TIMED_WAITING不要慌那大概率只是线程在空闲等任务。真正需要警惕的是BLOCKED和WAITING大量堆积且长时间不退尤其是配合线程池队列长度持续上涨那多半是池子里的线程全堵在业务代码的锁上或者等待条件上了。这里顺便回应一个高频问题线程池的阻塞队列怎么选ArrayBlockingQueue有界、LinkedBlockingQueue可以无界也可以有界、SynchronousQueue不存任务。如果队列选无界那拒绝策略里的maxPoolSize基本是摆设任务全堆在内存里最终可能打爆堆内存。选型上我倾向于有界队列加CallerRunsPolicy宁可让提交任务的线程自己跑也别把内存拖垮。4.4 常见问题速查表现象可能的线程状态排查方向线程卡住不执行CPU正常BLOCKEDjstack看等哪把锁找锁持有者线程卡住不执行CPU也低WAITING检查是否缺少notify/unpark或join未结束线程一直跑CPU很高RUNNABLE检查死循环、自旋等待、无效空转大量线程TIMED_WAITING且可恢复空闲确认有任务进来能唤醒看队列积压线程池线程全部WAITING且业务停滞异常多半是业务逻辑进入不可恢复的等待5. 从状态出发把并发设计的底层逻辑串起来5.1 状态、锁、调度器三者是怎么配合的把六种状态看熟之后你会发现并发编程里很多设计都在围绕“怎么让线程在合适的时机进入合适的等待状态”展开。以ReentrantLock为例它基于AQS线程拿不到锁时不会进入BLOCKED而是被包装成Node放进同步队列然后调用LockSupport.park()此时线程状态是WAITING。为什么比synchronized的BLOCKED更精细因为AQS队列可以提供公平排队、超时获取、可中断获取这些能力而这些在monitor机制里实现起来非常别扭。有同学问AtomicInteger线程安全吗如果从状态角度去理解这个问题会更透彻CAS是CPU层面的原子指令线程不会进入BLOCKED或WAITINGCAS失败时线程仍在RUNNABLE自旋重试。所以高并发下AtomicInteger的性能损耗主要来自CPU缓存一致性流量而不是线程调度切换。这就是“锁”和“无锁”设计思路的根本分歧一个用状态等待换取公平和可控一个用CPU自旋换取低延迟和高吞吐。5.2 虚拟线程来了状态模型会变吗虚拟线程Virtual Threads这两年被聊得很多有人担心以前学的状态模型是不是白学了。我的看法是六种状态本身不会变变的是谁在承载这些状态。传统平台线程一个线程对应一个内核线程状态切换要经过内核。虚拟线程则跑在JVM内部的调度器上一个平台线程可以承载很多虚拟线程虚拟线程的阻塞不会直接阻塞底层平台线程。所以遇到大量IO密集的代码用虚拟线程能显著减少上下文切换开销。虚拟线程依然复用Thread的语义getState()依然能拿到NEW、RUNNABLE这些状态值。只不过阻塞的实现从内核级让位给了JVM级调度。面试如果被问到虚拟线程原理可以从“调度器把阻塞虚拟线程的载体平台线程释放出来继续跑别的虚拟线程”这个角度切入比空背概念有说服力得多。5.3 死锁的本质状态图上的环最后说一个和状态强相关的话题死锁。死锁的本质是多个线程在状态图上构成循环等待线程A持有锁1等锁2线程B持有锁2等锁1。从状态上看这两个线程都会是BLOCKED而jstack能直接检测出死锁Found one Java-level deadlock: ...输出会把两个线程的锁信息、等待信息并排打印出来非常直观。避免死锁的方法其实老生常谈按固定顺序加锁、用tryLock加超时、尽量缩小锁范围。但我想强调的是遇到死锁别只想着怎么背避免原则学会看jstack输出才是第一生产力。毕竟线上问题第一步永远是定位定位到了方案自然就出来了。写到最后我想多说一句个人体会。我在排查线上问题的时候超过一半的线程异常都能通过“看jstack、找状态、定位栈顶方法”这条路解决。六个状态看着简单用熟了就是一套高效的问题诊断框架。技术文档不会主动告诉你这些经验只有一遍遍看dump文件、一次次在压测环境里复现死锁才能形成条件反射。如果你现在正在学多线程别急着背一堆并发工具类的用法先把状态模型吃透后面学AQS、学线程池、学虚拟线程都会顺很多。

相关新闻

B2B2C电商平台功能清单编写指南:从角色权限到状态机拆解

B2B2C电商平台功能清单编写指南:从角色权限到状态机拆解

简介:这是一份B2B2C电商平台的功能清单文档,面向电商产品经理、系统开发人员及平台运营者,可用于需求梳理、功能规划与开发排期参考。文档按交易中心、消费者界面、商品搜索、商品列表页、商品详情页、购物车、订单管理、会员中心、账户管理等…

2026/10/11 1:19:24 阅读更多 →
用机器学习分析双色球:从数据清洗到特征工程的完整实践

用机器学习分析双色球:从数据清洗到特征工程的完整实践

简介:面向机器学习入门者与数据预测爱好者的实战资料包,以“采用机器学习分析双色球”为切入点,完整呈现从数据收集、清洗、独热编码、特征工程到模型训练、交叉验证与参数调优的端到端流程。资源共29个文件,以16个Python脚本为核…

2026/10/11 1:19:24 阅读更多 →
PJ85718DM与MK24FN1M0VDC12温控节点设计实战

PJ85718DM与MK24FN1M0VDC12温控节点设计实战

1. 项目概述:为什么两个看似普通的芯片组合能撑起温控系统的“神经末梢”PJ85718DM 和 MK24FN1M0VDC12 这两个型号,初看只是电子元器件目录里两行不起眼的代码——前者是某厂商推出的高精度、低功耗数字温度传感器,后者是恩智浦(N…

2026/10/11 1:19:24 阅读更多 →

最新新闻

本地Figma Agent:绕过API限制解析.figma文件的轻量代码代理

本地Figma Agent:绕过API限制解析.figma文件的轻量代码代理

1. 项目概述:为什么一个“本地运行的Figma Agent”突然成了设计与开发协同的新焦点最近在几个前端协作群和设计工具讨论区里,频繁刷到一个词:Local Figma Agent MCP。它不是Figma官方插件,也不依赖云端API密钥或企业级订阅&#x…

2026/10/11 2:16:56 阅读更多 →
为什么我依然坚持纯C编写系统工具:百KB二进制与零动态依赖的工程价值

为什么我依然坚持纯C编写系统工具:百KB二进制与零动态依赖的工程价值

在云原生工具链动辄采用Go、Rust重构一切的潮流下,一个简单的日志收集Agent或状态巡检CLI工具,编译出的二进制文件体积普遍突破20MB至50MB。许多年轻工程师对此习以为常,认为“磁盘和内存这么便宜,多占几十兆算什么”。然而&#…

2026/10/11 2:16:56 阅读更多 →
ESP8285+MQTT直流电机控制器实战:从硬件选型到联调排错

ESP8285+MQTT直流电机控制器实战:从硬件选型到联调排错

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 2:16:56 阅读更多 →
如何快速完成子域名枚举与域名历史调查:theHarvester + Wayback Machine 组合技完全指南

如何快速完成子域名枚举与域名历史调查:theHarvester + Wayback Machine 组合技完全指南

如何快速完成子域名枚举与域名历史调查:theHarvester Wayback Machine 组合技完全指南 【免费下载链接】Legendary_OSINT A list of OSINT tools & resources for (fraud-)investigators, CTI-analysts, KYC, AML and more. 项目地址: https://gitcode.com/…

2026/10/11 2:16:56 阅读更多 →
刷完 500 道算法题后的顿悟:算法培养的是思维的秩序,而不是死记硬背

刷完 500 道算法题后的顿悟:算法培养的是思维的秩序,而不是死记硬背

工位桌角压着三本翻烂了的算法书,右侧显示器上 LeetCode 的打卡日历已经连续亮了快两年,累计通过题数悄悄跳过了 500。 从大四保研后的无知与焦虑,到研一在实验室刷题被 Hard 题虐得怀疑人生,再到研二秋招面对大厂面试官高压手撕代…

2026/10/11 2:16:56 阅读更多 →
dirsearch 目录扫描实战:从 CTF 卡壳到渗透测试工作流

dirsearch 目录扫描实战:从 CTF 卡壳到渗透测试工作流

简介:dirsearch-master.zip 是一款基于 Python3 开发的 Web 目录扫描工具源码包,面向渗透测试人员、安全研究者及 CTF 参赛选手,用于探测服务器上未公开的隐藏目录与敏感文件,帮助发现潜在漏洞与关键信息。压缩包共 88 个文件&…

2026/10/11 2:15:55 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →