Lock与Condition实现生产者消费者:精准唤醒与并发协作实践
简介这份PDF面向Java多线程初学者与需要深入理解并发协作的中级开发者以Lock与Condition为切入点讲解生产者消费者模式如何通过显式锁与条件队列实现线程间的安全协作解决了传统synchronized和wait/notify在锁粒度控制、多条件等待方面不够灵活的问题。文档从ProducerConsumerDemo类的共享缓冲区设计讲起完整展示了ReentrantLock保证互斥、condition.await()释放锁并进入等待、condition.signalAll()唤醒全部等待线程的完整流程并特别解释了为什么缓冲区满/空时要用while循环判断而不是if以避免虚假唤醒造成的越界生产或消费。除了基础流程文档还补充了InterruptedException异常处理、tryLock()非阻塞获取锁以及ArrayBlockingQueue等内置阻塞队列的替代方案帮助读者在实际项目中根据场景选择合适的同步机制。资源包仅含1个PDF文件大小27KB内容紧凑方便随时查阅目前已有318人学习下载无论是备考Java并发编程还是复习生产者消费者模式这份示例都能提供清晰的代码级参考。通过学习读者可以掌握使用Lock与Condition编写可靠生产者消费者模型的能力并灵活迁移到任务队列、数据缓存、连接池等业务场景。1. 用 Lock 和 Condition 手写生产者消费者到底比 BlockingQueue 多得到了什么生产环境里一个 ArrayBlockingQueue 就能解决的生产者消费者场景为什么还要用 Lock 和 Condition 自己写因为有些管道需要精细控制流量、需要多路唤醒、需要异常恢复而 BlockingQueue 的黑匣子行为在高压下并不总是透明的。这篇文章用一个 100 行不到的仓库模型从 wait/notify 讲到多 Condition 的并发姿势适合读得懂 synchronized 但还没把 Condition 用熟的开发者也适合想把线程协作从「碰运气」变成「看得清」的人。读完你能拿到一份可以直接跑的最小示例代码以及 5 个实操里真实踩过的坑最后还有一个多生产多消费下的验证方法避免上线前心里没底。2. 先弄懂 Lock 和 Condition它和 wait/notify 到底差在哪2.1 有了 synchronized为什么还要引入 Lock很多项目里的线程协作一开始都是从 synchronized 加 wait/notify 写起的。synchronized 的问题不是不能跑而是太粗糙一个监视器锁只有一个等待集合所有没满足条件的线程都睡在同一张床上。生产者想等「仓库有空位」消费者想等「仓库有数据」这两个等待原因完全不一样却被强制塞在同一个等待队列里。notify 只能随机叫醒一个线程你没法保证叫醒的是消费者还是另一个生产者notifyAll 虽然能把所有人都叫醒但代价是所有人重新抢锁、重新判断条件大量线程做了无用功。Lock 接口解决的就是这个粒度问题。ReentrantLock 是显式锁支持可中断获取、超时获取、公平与非公平策略这些 synchronized 都没有。但真正让 Lock 在生产者消费者模式里脱颖而出的是它配套的 Condition。一个 ReentrantLock 可以 new 出多个 Condition每个 Condition 维护一条独立的条件等待队列。生产者等 notFull消费者等 notEmpty两条队列互不干扰唤醒时也能精准投递。这是我愿意在项目里从 synchronized 迁移到 Lock 的主要理由不是为了炫技是为了减少无效唤醒和排队竞争。2.2 Condition 与 wait/notify 的映射await、signal、signalAll如果你熟悉 wait 和 notifyCondition 的 API 几乎可以一一对应await 对应 waitsignal 对应 notifysignalAll 对应 notifyAll。但这里有三个关键差异直接影响你写代码的方式。第一synchronized 的 wait 只能在 synchronized 块里调用而 Condition 的 await 只能在持有对应 Lock 时调用它同样会释放当前持有的锁但释放的是 Lock 而不是内置监视器。第二await 支持超时版本 await(long time, TimeUnit unit)await 期间还响应中断这意味着线程不会因为某个条件永远不满足而无限期挂死。第三signal 只是把等待线程从条件队列移到锁队列中被移出的线程需要重新参与锁竞争而不是立刻继续执行。很多人第一次写 Condition 时以为 signal 之后线程马上就往下走实际不是这样。这里有一个最容易被忽略的点await 返回后线程并不代表条件已经满足。线程醒来只是说明「它有了重新检查条件的机会」条件可能仍然不成立。比如两个消费者同时被 signal 唤醒但仓库里只有一份数据抢到锁的消费者取走了数据另一个消费者拿到锁时仓库已经空了它必须再次等待。这就是为什么标准写法里判断条件必须用 while 而不是 if。我一般会把这个规则记成一句话await 永远被放在 while 循环里醒来的第一件事是重新检查而不是直接消费。2.3 为什么两个 Condition 比一个 Condition 更精准用一个 Condition 实现生产者消费者是完全可行的put 和 take 都操作同一个条件变量但效率上会有明显的缺陷。假设生产者完成一次生产后调用 signal此时等待队列里既有生产者也有消费者signal 唤醒谁是不确定的如果唤醒的是另一个生产者它醒来后发现自己等的是「有空间」而仓库又满了只能再次睡回去这就是一次无效唤醒。改用 signalAll 也一样所有线程同时醒来互相竞争锁最终只有少数线程能真正推进其余全部白醒一场。两个 Condition 的写法是典型的生产者消费者标准答案。notEmpty 队列专门睡等待数据的消费者notFull 队列专门睡等待空间的生产者。put 操作完成之后调用 notEmpty.signal只可能唤醒消费者take 操作完成之后调用 notFull.signal只可能唤醒生产者。唤醒精准了线程切换少了锁竞争也小。在仓库容量小、生产消费频率高的场景里这个差距会被放大得非常明显。所以我做某跨平台系统的消息管道时只要需要手动控制线程协作第一选择就是双 Condition。如果只是简单的任务分发BlockingQueue 仍然更合适这点到最后一章会细说。3. 最小可运行示例仓库模型与三处必调参数3.1 完整示例代码一个仓库类加上一生产一消费代码是最有说服力的。下面这个示例不依赖任何框架纯 JDK 并发包实现。我用 LinkedList 模拟仓库容量由构造参数决定生产者往尾部放数据消费者从头部取数据一放一取天然符合 FIFO。你可以直接复制运行。import java.util.LinkedList; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class SimpleStorage { private final LinkedListInteger items new LinkedList(); private final int capacity; private final ReentrantLock lock new ReentrantLock(); private final Condition notEmpty lock.newCondition(); private final Condition notFull lock.newCondition(); public SimpleStorage(int capacity) { this.capacity capacity; } public void put(int value) throws InterruptedException { lock.lock(); try { // 必须用 while 而不是 if防止虚假唤醒后越过容量检查 while (items.size() capacity) { notFull.await(); } items.addLast(value); notEmpty.signal(); } finally { lock.unlock(); } } public int take() throws InterruptedException { lock.lock(); try { while (items.isEmpty()) { notEmpty.await(); } int value items.removeFirst(); notFull.signal(); return value; } finally { lock.unlock(); } } }启动代码负责创建仓库、启动生产者和消费者线程。public class ProducerConsumerDemo { public static void main(String[] args) throws Exception { SimpleStorage storage new SimpleStorage(3); Thread producer new Thread(() - { for (int i 1; i 10; i) { try { storage.put(i); System.out.println(produced: i); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } }, producer); Thread consumer new Thread(() - { for (int i 0; i 10; i) { try { int value storage.take(); System.out.println(consumed: value); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } }, consumer); producer.start(); consumer.start(); producer.join(); consumer.join(); System.out.println(all done); } }运行结果里 produced 和 consumed 会交替出现顺序不固定但最终能配成 10 对。如果生产量变成 1000、消费量变成 1000这个程序依然能稳定跑完不会死锁也不会丢数据这正是 Condition 协作的核心价值。3.2 逐段拆解await 释放锁、signal 不释放锁、while 循环先把 put 方法的执行流程走一遍。生产者调用 put第一件事是 lock.lock() 拿锁。拿到锁之后检查 items.size() capacity仓库满就进入 notFull.await()。await 会做三件事释放当前持有的锁、把当前线程挂起、加入 notFull 条件队列。线程在这里睡住直到某个消费者 take 之后调用 notFull.signal()线程才会从条件队列移到锁队列重新参与锁竞争。它获得锁后从 await 返回但此时不能直接 addLast必须回到 while 循环再检查一次容量。这就是 while 的价值避免虚假唤醒和竞争带来的越界写入。signal 的调用时机也值得说。put 方法里 notEmpty.signal() 调用时当前线程仍然持有锁signal 只是把等在 notEmpty 队列里的某个消费者移动到锁队列并不会释放锁。真正释放锁是走到 finally 里的 lock.unlock()。所以消费者被唤醒后并不会马上执行它要等生产者完全退出临界区并释放锁然后去抢锁。这个顺序是 Condition 机制设计的核心也是新手最容易误解的地方。如果有人在 unlock 之后再调用 signalReentrantLock 会直接要求当前必须持有锁运行时就会抛出 IllegalMonitorStateException这一点非常容易踩。take 方法完全对称。消费者拿锁后检查仓库是否为空空就 await被生产者唤醒后重新检查不为空才 removeFirst。这里要注意的是removeFirst 操作本身在锁保护内对 LinkedList 的修改是线程安全的。我之前在某图像处理 Demo 里偷懒直接把锁去掉结果生产环境偶发报了 NoSuchElementException排查了大半天才发现是消费者在空列表上取数据本质上就是条件的判断被绕过了。3.3 三个必调参数容量、公平性、等待超时第一个必调参数是仓库容量 capacity。容量为 1 时生产者和消费者基本是严格交替执行你一步我一步吞吐量最低但内存占用最小容量调大后生产者可以连续生产多条再休息消费者也能攒批消费吞吐量会明显上升代价是数据在管道里的停留时间变长。我的习惯是先按单条消息大小和允许的最大延迟估算出一个粗值再通过压测微调而不是拍脑袋定一个 128 或 1024。第二个必调参数是 ReentrantLock 的公平性。构造函数 new ReentrantLock() 默认非公平线程抢锁凭运气吞吐量高但极端情况下可能出现线程饥饿new ReentrantLock(true) 会按等待时间排队分配锁线程更公平但锁切换开销更大。生产者消费者场景里我一般保持默认非公平除非有明确的服务质量要求比如某个任务必须在限定时间内被处理否则没必要为公平性付出吞吐代价。第三个必调参数是 await 的超时时间。如果线程在 await 里无限等待一旦对应的 signal 因为 bug 没发出程序就永久挂死。我一般会改成 notFull.await(3, TimeUnit.SECONDS) 这种写法超时后返回 false再根据返回值和当前状态决定是继续重试还是放弃。注意 await 超时不等同于锁超时lock.tryLock(3, TimeUnit.SECONDS) 是拿锁超时await 超时是等条件超时两者语义完全不同第 4 章会专门讲这个坑。4. Lock/Condition 落地避坑5 个真实会踩的并发问题4.1 把 while 写成 if空仓库上取数据直接翻车现象消费者线程偶尔抛出 NoSuchElementException但程序并不是必现跑几十次才出现一次线上日志无法稳定复现。 原因判断条件用 if 而不是 while。消费者被 signal 唤醒后直接走到 removeFirst但此时仓库可能是空的。为什么会空因为可能有多个消费者同时等在 notEmpty 队列上生产者只放了一条数据signal 唤醒了其中一个消费者它抢到锁取走数据另一个消费者也被唤醒了它抢到锁后没有重新检查仓库状态直接在空链表上执行 removeFirst异常就发生了。 解决把 if 换成 while。这不是风格问题是 Condition 使用的强制要求只要条件判断是和 await 配对使用的一律用 while 循环。我也被这个问题坑过一次那个「玄学」bug 最后查出来就是一行 if 的锅。4.2 signal 写错了队列生产者等了半天也没被唤醒现象仓库满了生产者线程阻塞在 notFull.await()消费者不断取走数据日志显示生产者和消费者都活着但生产就是永远不恢复。 原因take 方法里把 notFull.signal() 写成了 notEmpty.signal()。消费者完成消费后只唤醒等待数据的消费者而等待空间的生产者还睡在 notFull 队列里没有收到任何通知。这属于复制代码时改漏了对象名但排查时很容易忽略因为代码能编译、能运行只是逻辑死锁。 解决写完后把 put 和 take 的 signal 对象对照检查一遍生产完成唤醒 notEmpty消费完成唤醒 notFull。我的习惯是把这两个 Condition 的命名和用途直接写在变量声明旁边即使这样也拦不住手滑。遇到线程挂死不报错的场景先看唤醒用的是哪个 Condition再看唤醒的方向对不对。4.3 吞掉 InterruptedException线程中断状态丢失现象程序停止时调用线程的 interrupt() 想让它退出但线程没有任何反应继续卡在 await 里进程无法优雅关闭。 原因catch 块里直接写了注释或者空语句没有处理中断状态。await 抛出 InterruptedException 后会把线程的中断状态清除如果 catch 里不做任何事线程就丢失了被中断的信号程序只能强制杀掉。 解决在 catch 里调用 Thread.currentThread().interrupt() 恢复中断状态然后 return 退出循环。这既保留了中断信息也让上层逻辑能感知到线程是被中断而非正常结束。我踩过这个坑之后凡是有 await 或 sleep 的代码catch 块里第一行必然是 interrupt() 恢复已经成了肌肉记忆。4.4 await 超时当成锁超时等条件的时间全耗在抢锁上现象设置了 await(5, TimeUnit.SECONDS)但线程还是经常超过 5 秒才恢复有时候甚至等了 10 多秒。 原因await 超时等待的是「条件被通知」的时间不包含等待获取锁的时间。线程从 await 返回后它还在锁队列里排队其他线程持有锁的时间越长它恢复执行就越晚。如果还有多个等待者竞争同一把锁总耗时可能远大于 5 秒。这是把 await 超时和 lock.tryLock 超时混为一谈造成的误判。 解决先明确自己到底想限制哪一步。拿锁阶段用 tryLock(timeout)条件等待阶段用 Condition.await(timeout)两个超时可以配合使用。如果业务要求整体响应时间可控可以在两个阶段都设超时并在超时后走降级分支而不是赌某一边一定能在时间内完成。4.5 多消费者场景下信号丢失部分线程永远睡下去现象改成两个消费者线程后生产者放了很多数据但某些消费者线程始终不消费日志里没有任何输出线程状态显示 WAITING。 原因put 方法用了 notEmpty.signal() 而不是 signalAll()。双 Condition 下 signal 确实只投递给消费者但如果多个消费者同时在等生产者每生产一条只叫醒一个消费者而消费者可能取完一条又继续睡整体上每个消费者都有机会不存在永久丢失。真正的问题出在单 Condition 版本或者混合唤醒逻辑里signal 可能叫醒的是生产者消费者队列没人叫醒等待的消费者就永久睡眠。 解决如果真正用了两个 Conditionsignal 是够用的因为每个 Condition 只睡同一种角色如果项目里为了省事用了单 Condition必须改成 signalAll 并用 while 兜底。最稳妥的排查方式是把所有线程 dump 出来看 WAITING 线程的 stack trace停在哪个 await 上就能反推出是谁忘了发信号。5. 从能跑到跑稳多生产多消费下的验证方法与压测技巧手动写的 Lock、Condition 代码最怕一件事单测能过多线程一跑就出问题。我的验证方法是固定总量配合计数器让多个生产者和多个消费者同时跑最后断言消费总数必须等于生产总数。下面是一个可复用的骨架。int total 1000; SimpleStorage storage new SimpleStorage(4); AtomicInteger consumed new AtomicInteger(); int producerThreads 2; int consumerThreads 2; Thread[] producers new Thread[producerThreads]; for (int t 0; t producerThreads; t) { producers[t] new Thread(() - { for (int i 0; i total / producerThreads; i) { try { storage.put(1); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } }); } Thread[] consumers new Thread[consumerThreads]; for (int t 0; t consumerThreads; t) { consumers[t] new Thread(() - { while (consumed.get() total) { try { storage.take(); consumed.incrementAndGet(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } }); } // 启动所有线程并 join最后断言 consumed.get() total这个骨架里有几个细节。消费者的 while 条件用 consumed.get() total保证消费线程不会提前退出AtomicInteger 替代 int 避免多线程下的可见性问题最终断言用 。跑过几百次如果断言都通过说明生产消费基本配对正确。这个验证方式不算严格证明但作为上线前的回归手段足够用。压测方面容量是最值得调的参数。下面这组观察关系可以帮你快速定位瓶颈容量行为特征主要风险1生产消费严格交替线程切换频繁吞吐量低4-16缓冲充分吞吐平稳需要压测确定最优值过大生产者几乎不阻塞内存占用上升数据延迟变高压测时先固定线程数只调容量看总耗时和内存曲线再固定容量调线程数观察锁竞争情况。如果压测中消费者一直追赶不上生产者优先看消费端逻辑耗时而不是盲目调大容量。容量只是缓冲不是解决消费慢的方案。我现在的习惯是先判断能不能直接上 BlockingQueue能就绝不手写只有需要多路精确唤醒、需要超时控制、需要异常恢复时才用 Lock 和 Condition。一旦上手while 循环、超时兜底、中断恢复这三件套必须写齐缺一个都不敢上线。排查线程不结束的问题时永远按「等待谁、通知谁、谁来唤醒它」的顺序找而不是到处打印日志碰运气。这套方法帮我避过好几次生产事故希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Linux 上重装 Oracle 11gR2 完整图解:依赖包、内核参数与 DBCA 建库避坑指南

Linux 上重装 Oracle 11gR2 完整图解:依赖包、内核参数与 DBCA 建库避坑指南

简介:这份文档面向具备一定Linux与数据库基础的IT运维及DBA人员,系统讲解在Linux单机环境下安装Oracle 11g Release 2的完整流程。内容围绕前期package准备、Oracle用户与组创建、环境变量配置、runInstaller启动、安装类型与组件选择、Inventory目录指定…

2026/10/17 19:55:04 阅读更多 →
机器学习入门:吃透学习系统四部件与三大分类,避开认知坑

机器学习入门:吃透学习系统四部件与三大分类,避开认知坑

简介:机器学习入门介绍PPT课件,是《人工智能原理与应用》课程第7章的教学幻灯片,围绕“机器学习”的基本概念,系统讲解学习的本质、机器学习定义、学习系统应具备的条件与能力,以及由环境、学习、知识库、执行与评价构…

2026/10/17 19:55:04 阅读更多 →
DeepSeek-R1:面向中文逻辑推演的可验证推理引擎

DeepSeek-R1:面向中文逻辑推演的可验证推理引擎

简介:本资源是北京大学DeepSeek系列研讨讲座的配套讲义《DeepSeek与AIGC应用》,面向AI初学者、教育科研人员及AIGC工具实践者,旨在破除仅停留在操作层面的浅层认知,系统厘清DeepSeek-R1推理模型的技术原理、能力边界与真实应用场景…

2026/10/17 19:55:04 阅读更多 →

最新新闻

会议室预订小程序全栈源码:后端冲突检测与前后端联调实践

会议室预订小程序全栈源码:后端冲突检测与前后端联调实践

简介:这是一套专为写字楼、高校、创业园区等场景打造的会议室预订预约小程序前后台源码。前端基于微信小程序技术,后台采用原生PHP开发,提供用户友好的预约界面与灵活的管理机制,支持二维码现场核销、定时/临时预约等常用功能&…

2026/10/18 2:52:04 阅读更多 →
163MusicLyrics:批量提取网易云与QQ音乐的 LRC 歌词

163MusicLyrics:批量提取网易云与QQ音乐的 LRC 歌词

163MusicLyrics:批量提取网易云与QQ音乐的 LRC 歌词 【免费下载链接】163MusicLyrics 云音乐歌词获取处理工具【网易云、QQ音乐】 项目地址: https://gitcode.com/GitHub_Trending/16/163MusicLyrics 你有一批 MP3 想配上 LRC 歌词,却只能一首一首…

2026/10/18 2:52:04 阅读更多 →
高校学工系统选型:成熟产品还是深度定制?混合架构更香

高校学工系统选型:成熟产品还是深度定制?混合架构更香

1. 选型逻辑:到底该买成品还是自己造“学工系统哪家强”这个问题,几乎每年开学季都会被推到风口浪尖。作为在校内信息化部门摸爬滚打多年的从业者,我也经常在行业群里被同行追着问:到底选成熟产品还是找团队深度定制?说…

2026/10/18 2:52:04 阅读更多 →
网页文本提取与Word生成:JS脚本和Python爬虫搞定文库文档

网页文本提取与Word生成:JS脚本和Python爬虫搞定文库文档

前阵子遇到一个挺典型的场景:有同学需要把文库页面上能看到的正文整理成Word发给大家,但页面上的文本既选不中、也复制不了,直接下载又提示要会员。折腾了一晚上之后,我搞定了两条路线——一条是js脚本下载百度文库生成word文本&a…

2026/10/18 2:52:04 阅读更多 →
Pygame运动底层原理:坐标系、帧率与视觉错觉

Pygame运动底层原理:坐标系、帧率与视觉错觉

1. 这不是“动效教程”,而是游戏逻辑的底层拆解你点开这个标题,大概率是刚学完 Pygame 基础绘图,画出了一个方块、一张图片、甚至让角色左右移动了两下——但下一秒就卡在“怎么让背景跟着动?”“为什么人物一跑背景就撕裂&#x…

2026/10/18 2:52:04 阅读更多 →
ERP实施项目启动会:从材料准备到会后跟进的全流程实战指南

ERP实施项目启动会:从材料准备到会后跟进的全流程实战指南

简介:这份PPT面向企业信息化负责人、ERP项目经理及实施顾问,聚焦大中型ERP软件实施项目启动会这一关键环节,帮助读者理解项目正式启动阶段的组织方式与沟通要点。压缩包内共1个pptx文件,约2.32MB,以幻灯片形式呈现&…

2026/10/18 2:51:04 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 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/18 0:55:02 阅读更多 →
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/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练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/16 14:23:36 阅读更多 →