Java多线程入门:线程创建、状态与线程安全锁机制详解
今年上半年我帮同事调一个批量数据采集服务单线程处理时经常要等数据库慢查询、等上游接口响应整批任务跑下来耗时忽高忽低。改成多线程并发处理后吞吐量直接翻了一倍多那个项目让我意识到Java多线程不只是一个面试考点更是实际项目里绕不开的基础能力。很多刚学完Java基础的读者问我多线程该从哪入手今天这篇就把最核心的概念、创建方式、线程状态、线程安全和锁这些入门必踩的坎一次性讲清楚配合可直接运行的代码示例适合准备系统的学一遍并动手实操。1. 先搞清楚线程到底在解决什么问题1.1 什么是进程什么是线程进程和线程这两个概念很多教程一上来就抛定义背了容易忘。我用一个类比帮助理解进程就像一个独立的车间每个车间有自己的原料仓库和机器设备车间之间互不干扰线程就是车间里的工人同一个车间里的工人共享仓库里的原料但每个人有自己的工具箱存放自己的工具和临时材料。对应到Java程序里启动一个main方法就是启动一个进程JVM会为这个进程分配独立的内存空间。进程内部可以同时执行多条执行路径每条路径就是一个线程。同一进程下的多个线程共享堆内存和方法区每个线程独享自己的虚拟机栈和程序计数器。一个线程挂了不会导致整个进程退出但多个线程同时修改同一个对象就会产生数据竞争问题这也是后面要重点讨论的线程安全问题的来源。1.2 多线程给程序带来什么实际收益多线程真正的价值来源于两个事实。第一个事实是现在的CPU基本上都是多核的。单线程程序在4核机器上运行时同一时刻只占用了四分之一的处理能力其余核心处于空闲状态。如果任务能被拆分成多个相对独立的片段多线程并行执行就能充分利用硬件资源让整体完成时间显著缩短。比如我有一个音频转码的小工具单线程处理一批文件要二十秒拆成四条线程并行跑耗时能压到六秒左右。第二个事实是程序执行过程中存在大量等待。网络请求要等响应磁盘文件要等IO数据库查询要等返回这些等待时间里CPU其实闲着。如果一个线程在等待IO时能把CPU让给其他线程去执行计算任务就能提高资源利用率提升系统整体吞吐量。典型例子就是Web服务器处理大量并发请求不能因为一个请求在等数据库就把其他请求都卡在原地。1.3 什么场景才真正需要多线程我见过不少初学者拿到任务就条件反射地想开多线程觉得自己用了线程池就显得高级。实际上多线程不是万能的用错场景反而引入更多问题。要不要用多线程得先看任务类型。IO密集型任务是最适合多线程的场景文件读写、HTTP调用、数据库访问、消息队列消费这类任务大部分时间花在等待上多线程可以把这个等待时间重叠起来。计算密集型任务也能用多线程比如图像处理、数据统计分析、加密计算拆分后分给不同核心并行跑但线程数通常建议和CPU核数相当再多了只会增加上下文切换开销。异步流程控制也离不开多线程。用户下单成功后要发通知邮件、写日志、更新积分如果把邮件发送放在主流程里同步执行用户会明显感觉下单响应变慢。这时候另起线程异步处理主流程立刻返回成功提示体验就完全不同。反过来任务本身简单、执行时间很短或者多个任务之间有强依赖、需要严格按顺序执行那就不值得引入多线程。共享状态复杂、难以保证同步正确性的场景也要谨慎。多线程不是银弹引入之前先想清楚收益和成本。2. 创建线程的几种常用方式2.1 继承Thread类最直观但最不推荐最早接触多线程时教程通常先讲继承Thread类这种方式最直观也最容易理解。public class MyThread extends Thread { Override public void run() { System.out.println(Thread.currentThread().getName() 正在执行); } public static void main(String[] args) { MyThread t new MyThread(); t.start(); } }启动线程调用的是start()方法不是run()方法。start()会让JVM创建一个新线程由新线程去调用run()里的代码。如果直接调用run()那就只是普通方法调用还是在当前线程里执行没有并发效果。这种方式的问题在于它把任务代码直接写在了Thread类的子类里导致任务逻辑和线程对象强耦合。继承本身就意味着这个类不能再继承其他类在Java这种单继承语言里代价很高。实际开发中我几乎不会直接继承Thread去写业务逻辑这个写法属于认识阶段的内容真正做项目时不推荐。2.2 实现Runnable接口把任务和线程拆开实现Runnable接口是更合理的做法因为它把“要执行的任务”和“承载任务的线程”分开了。任务本身只是实现一个run()方法线程对象只是执行任务的载体。public class RunnableTask { public static void main(String[] args) { Runnable task () - System.out.println(Thread.currentThread().getName() 正在执行); Thread t1 new Thread(task, worker-1); Thread t2 new Thread(task, worker-2); t1.start(); t2.start(); } }这里用Lambda简写了一个Runnable实现代码短了很多。同一个task可以被塞给多个线程去跑适合多个线程执行同一份任务的场景。由于Runnable只是一个接口实现类还能再继承别的类扩展性比继承Thread好得多。还有一个容易被忽略的好处后面线程池提交任务时接受的就是Runnable和Callable不是Thread子类。所以早点习惯用Runnable后续学习线程池会顺畅很多。2.3 用Callable拿到线程执行结果Runnable的run()方法没有返回值也不能抛受检异常。如果希望线程执行完返回一个结果比如让线程去计算一个数值计算完再拿回来用Runnable就做不到了。这时候要用Callable配合FutureTask。import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class CallableTask { public static void main(String[] args) throws Exception { CallableInteger task () - { Thread.sleep(1000); return 100; }; FutureTaskInteger futureTask new FutureTask(task); Thread thread new Thread(futureTask); thread.start(); Integer result futureTask.get(); System.out.println(计算结果 result); } }FutureTask是Runnable的一个实现所以可以直接传给Thread去启动。同时它内部又持有Callable的执行结果调用get()方法可以阻塞等待线程执行完再把结果取出来。Callable的call()方法可以抛异常异常调用方也能拿到。这段代码里我让任务先睡了一秒模拟耗时计算。执行时会发现get()会一直等到线程结束才返回结果这就是阻塞等待的含义。实际项目中Callable结合线程池使用的频率很高比如并发查询多个接口后汇总数据非常适合这个模式。2.4 三种创建方式的选型对比三种创建方式各有适用场景做一个对比表格更直观。创建方式是否有返回值能否抛异常代码耦合推荐程度继承Thread否否任务与线程耦合不推荐实现Runnable否否任务与线程分离推荐实现Callable是是任务与线程分离支持结果返回需要结果时推荐实际写代码时我的习惯是不需要返回值的任务用Runnable需要返回结果或需要捕获异常的任务用Callable继承Thread的方式基本上只在面试题和旧代码里看到了。2.5 从第一天就建立线程池意识直接new Thread()启动线程的方式有两个明显的问题。第一线程创建和销毁本身有开销如果任务很频繁这种开销会被无限放大。第二线程数不受控制一旦任务量上来了系统可能瞬间创建几百个线程内存吃不消上下文切换也会拖垮性能。线程池的核心思路是复用一个固定数量的线程集合往池子里提交任务就行线程池内部负责调度和复用。Java里最常用的是ThreadPoolExecutor以及便捷的Executors工厂方法。这一篇不展开讲线程池的具体配置但要明确一个观念以后在项目里能用线程池就别直接裸启动线程。带着这个意识去学后面的并发知识方向不会跑偏。3. 线程状态与生命周期3.1 Java线程的六种状态Thread类里定义了一个枚举Thread.State包含六个状态。很多新手把线程状态和操作系统的线程状态混在一起容易绕进去建议先只盯住Java层面的这六种。状态含义触发场景举例NEW线程创建了还没调用start()new Thread()之后RUNNABLE可运行状态可能正在执行也可能在等CPU时间片start()调用后BLOCKED等待获取锁处于阻塞状态等待进入synchronized同步块WAITING无限期等待另一个线程执行特定动作调用wait()、join()TIMED_WAITING有限期等待调用sleep(ms)、wait(ms)、join(ms)TERMINATED线程执行完毕run()正常返回或抛出未捕获异常注意RUNNABLE这个状态比较特殊它把操作系统里的“运行中”和“就绪”合并成了一个状态。在线程运行过程中CPU时间片被抢占时线程从运行状态退出来但在Java层面状态依然是RUNNABLE。所以只凭getState()返回RUNNABLE无法判断线程此刻到底在被执行还是在排队等时间片。3.2 状态转移的关键方法引起线程状态变化的方法很多初学者最容易搞混的是sleep、wait、join、yield这几个。它们的共同点是都会让当前线程停一下但停下来的状态和是否释放锁完全不同。sleep(long ms)让当前线程休眠指定毫秒进入TIMED_WAITING。它不释放任何锁其他线程在此期间依然无法进入被sleep线程持有的同步块。wait()让当前线程释放持有的锁进入WAITING。它必须在synchronized块或synchronized方法里调用否则会抛IllegalMonitorStateException。需要配合notify()或notifyAll()唤醒。join()当前线程等待调用join的线程执行完进入WAITING。比如主线程调用t.join()主线程会等t线程结束才继续往下走。yield()当前线程让出CPU执行权但状态不变化依然处于RUNNABLE。这个方法是试探性的JVM和操作系统不保证一定会让出去。表格里更好记方法进入状态是否释放锁是否需要同步代码块唤醒方式sleepTIMED_WAITING否否时间到自动唤醒waitWAITING是是notify/notifyAlljoinWAITING否否目标线程执行完yield不变否否无需唤醒3.3 小Demo观察线程状态变化光背状态六种名称没用动手打印一遍印象才深。下面这段小代码可以观察线程状态的变化过程。public class StateDemo { public static void main(String[] args) throws Exception { Thread t new Thread(() - { try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); System.out.println(刚创建 t.getState()); t.start(); System.out.println(调用start后立刻 t.getState()); Thread.sleep(100); System.out.println(子线程sleep时 t.getState()); t.join(); System.out.println(子线程结束后 t.getState()); } }执行一次的结果大致是这样刚创建NEW 调用start后立刻RUNNABLE 子线程sleep时TIMED_WAITING 子线程结束后TERMINATED注意主线程调用t.join()会阻塞等待子线程执行完所以最后一行会在子线程终止后才打印。自己写代码时可以在子线程里分别调用sleep、wait、join配合getState()打印状态把状态流转的整个过程亲眼验证一遍记忆会深刻很多。3.4 新手常犯的run()和start()错误run()方法和start()方法的问题是入门阶段最高频的错位这里专门强调。public class WrongWay { public static void main(String[] args) { Thread t new Thread(() - System.out.println(Thread.currentThread().getName())); t.run(); t.start(); } }执行结果类似这样main Thread-0第一行打印的是main说明调用run()只是在主线程里执行了一段普通方法没有创建新线程。第二行打印Thread-0这才是真正的新线程。所以判断有没有启动新线程不要看run()里的代码被没被执行而是看执行它的线程是谁。还有一个细节start()方法只能调用一次。如果连续调用两次第二次会抛出IllegalThreadStateException。因为线程状态从NEW转为RUNNABLE之后就不能回退到NEW了。这个异常看起来突兀本质原因是生命周期规定如此。4. 线程安全与锁入门必踩的坎4.1 什么是线程安全线程安全的定义可以这样理解多个线程同时访问共享数据时在不做额外控制的情况下程序结果依然完全正确。反过来就是不安全。最容易出问题的场景是多个线程同时更新同一个变量。比如一个计数器两个线程各自做一万次累加最后结果不一定是两万。因为count看起来是一行代码实际上在JVM里被拆成了三步读取当前值、算加一后的值、写回内存。两个线程的这三个步骤穿插执行时后面的写回会覆盖前面的结果等于一次更新被丢失了。这种丢失更新问题在现实项目里非常典型。某个电商系统里的库存扣减多个用户同时下单时如果没有锁保护库存变量可能出现超卖所以并发安全必须靠机制来保证。4.2 一个计数器翻车的例子先写一个没有并发保护的计数器。public class UnsafeCounter { private int count 0; public void increment() { count; } public static void main(String[] args) throws Exception { UnsafeCounter counter new UnsafeCounter(); Thread t1 new Thread(() - { for (int i 0; i 10000; i) { counter.increment(); } }); Thread t2 new Thread(() - { for (int i 0; i 10000; i) { counter.increment(); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(最终count counter.count); } }期望结果是20000实测多数时候会得到类似16784、19356这类比20000小的数字而且每次运行结果都可能不一样。这就是多个线程交叉执行导致的丢失更新。我在本机跑过一次两次结果分别差了三百多和一千多差异完全没有规律。4.3 synchronized基础的三种写法要让count变成原子操作一个简单的办法是用synchronized加锁。锁的核心语义是互斥同一时刻只有一个线程能进入被锁保护的代码区域其他线程只能在门外等待。同时它还有内存可见性的效果释放锁时会把修改刷新到主内存获取锁时会读取最新数据。第一种写法是修饰实例方法public class SafeCounter { private int count 0; public synchronized void increment() { count; } }这里锁的是当前实例对象this。两个线程必须持有同一个SafeCounter实例才能产生互斥效果。如果每个线程各new一个对象锁就失去意义了。第二种写法是修饰静态方法public class StaticCounter { private static int count 0; public static synchronized void increment() { count; } }静态方法锁的是Class对象即使有多个实例只要是对同一个类的静态方法加锁效果就是全局互斥。第三种写法是同步代码块可以灵活指定锁对象public class BlockCounter { private int count 0; private final Object lock new Object(); public void increment() { synchronized (lock) { count; } } }同步代码块的优势是加锁粒度可以缩小到真正需要保护的代码片段而不是锁住整个方法。比如一个方法里只有一行代码需要保护其余逻辑耗时很长那用同步代码块只锁这一行其他线程还能并发执行剩余部分吞吐量要好得多。把SafeCounter替换到之前的Demo里最终count就能稳定输出20000这就是加了锁和没加锁的区别。4.4 volatile不是万能药很多初学者听说volatile可以保证可见性误以为能替代synchronized还拿它去修饰计数器结果发现count依然不等于20000就困惑了。volatile的关键特性有两个一是保证共享变量的可见性一个线程修改了变量其他线程能立刻看到最新值二是禁止指令重排防止由于JVM优化导致执行顺序发生变化。但它不保证操作的原子性count这种读改写三步操作在并发环境下依然会互相覆盖。所以计数器场景用volatile修饰是不能解决线程安全问题的。那volatile什么时候有用一种是状态标志位一个线程写volatile boolean flag true另一个线程读这个flag来决定是否继续执行。写操作本身是原子性的可见性有保证不需要锁也能安全工作。另一种是双重检查锁定里为了保证单例对象创建完成前其他线程不会读到半初始化的对象会把实例对象声明为volatile。入门阶段记住一句话volatile管的是可见性和有序性不管原子性并发修改共享数据时还是得靠锁。4.5 锁的粒度怎么把握锁不是加得越多越好也不是越细越好。锁太粗临界区太大大量线程阻塞等待并发性能上不去锁太细又容易遗漏需要保护的共享操作出现难以复现的并发问题。我自己的经验是分两步。第一步先保证正确性把临界区划得宽一点把相关操作都保护起来让程序先稳定不翻车。第二步再结合性能测试看哪些操作耗时占了主导逐步缩小临界区范围。千万不要一开始就追求极致锁粒度边界算错一个线上数据错乱就麻烦了。锁对象的选择也有讲究。不要用字符串常量作为锁对象因为内容相同的字符串在多个地方可能指向同一个常量池对象容易造成锁蔓延。用this或Class对象时也要想清楚范围。最稳妥的做法是定义一个私有final的Object作为专用锁对象代码清晰也不会误锁。5. 常见问题与排查思路5.1 高频坑清单多线程入门阶段踩过的坑集中在下面几个。第一调用run()代替start()。表象是代码执行了但所有任务都在主线程串行跑完全没有并发的效果。查日志时发现打印的线程名全是main基本就是这个原因。第二多线程共享一个可变对象却没有同步。比如多个线程操作同一个List或同一个Map没有加锁就出现元素丢失、数据错乱甚至并发修改异常。第三在同步代码块里做耗时操作。某个线程拿着锁执行慢SQL或大文件读写其他线程全部阻塞等待整个系统的吞吐量瞬间下降。日志里能看到大量线程堆积在BLOCKED状态。第四用sleep循环等待某个条件成立。比如一个线程要等另一个线程把数据准备完直接写while (!ready) { Thread.sleep(10); }。这种做法既浪费CPU又容易出现可见性问题。更合适的方式是用wait/notify机制或者后续要学的并发工具类比如CountDownLatch。第五线程被中断时没有正确恢复标志。InterruptedException异常捕获后如果不调用Thread.currentThread().interrupt()重新设置中断标志上层代码判断isInterrupted()时会误以为线程没有被中断导致程序不能及时退出。5.2 简单排查手段多线程问题不像普通逻辑错误那样直接崩溃或抛异常它经常表现为偶发、间歇、难以稳定复现。遇到这种问题光靠看代码不太够需要靠工具观察线程运行环境。排查JVM线程状态最常用的组合是jps加jstack。先用jps查看Java进程的ID再通过jstack pid导出线程快照。快照里包含了每个线程的当前状态、栈调用、持有的锁和等待的锁。如果大量线程都停留在BLOCKED状态大概率是锁竞争太激烈如果大量线程停在WAITING可能是业务在等待某个条件触发比如没有合适的notify或者线程池队列已满。打印日志时也要带上线程上下文。在日志信息里嵌入Thread.currentThread().getName()线上排查时能把某一条路径上的日志串联起来。我习惯在关键入口处把线程名直接打出来哪怕看起来有点糙真出问题时定位速度快很多。还有一个实践技巧复现并发问题时想办法把并发程度放大。把线程数从两个加到二十个或者把一个很小的任务重复执行几十万次让竞态发生的概率变大这样问题更容易暴露出来修复验证也更有把握。5.3 一个抢票Demo实操理论讲再多不如自己动手跑一遍。这里用一个经典的模拟抢票演示来总结线程安全。先看不加锁的版本public class TicketSafe { private static int tickets 20; public static void main(String[] args) { for (int i 0; i 3; i) { new Thread(TicketSafe::loop, 窗口- (i 1)).start(); } } private static void loop() { synchronized (TicketSafe.class) { while (tickets 0) { try { Thread.sleep(5); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println(Thread.currentThread().getName() 卖出第 tickets 张票); tickets--; } } } }为了演示效果这个版本在同步块内直接循环卖票因此只有一个线程能进入卖票循环其他线程拿不到锁。从结果看票没有负数但输出的窗口只有第一个拿到锁的线程其他窗口完全没有机会卖票。这个例子说明锁保护的代码范围太大虽然安全但阻塞太严重。再看一个更合理的版本每个线程循环调用同步的卖票方法方法内部对“判票数和减票数”这两个步骤加锁保护。public class TicketSell { private static int tickets 20; public static void main(String[] args) { for (int i 0; i 3; i) { new Thread(TicketSell::loop, 窗口- (i 1)).start(); } } private static void loop() { while (tickets 0) { sell(); } } private static synchronized void sell() { if (tickets 0) { try { Thread.sleep(5); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println(Thread.currentThread().getName() 卖出第 tickets 张票); tickets--; } } }这里tickets变量在多个线程中读取理论上需要在循环条件处也考虑可见性。为了让Demo在复杂真实环境中更严谨可以将tickets声明为volatile。这样循环能快速看到最新值同时卖票方法内部依然靠synchronized保证原子性。跑出来的结果三个窗口都有机会卖票且不会出现重复卖同一张票的情况。去掉sell()上的synchronized跑一次马上能看到两个问题同一张票被两个窗口同时打印以及最终出现票数变负的情况。原因就是判断tickets 0和修改tickets这两步不在同一个锁保护里两个线程同时通过判断后各自执行减票必然把票数减过头。这个Demo把临界区的概念解释得非常直接——要安全就必须把“检查”和“执行”作为整体锁住中间不能被其他线程插进来。我个人在实际带的入门项目里发现90%的并发问题不是因为API不熟而是没想清楚临界区在哪里。你可以先把第4节的计数器例子跑上三五遍再把这个抢票Demo分别用加锁和不加锁的版本对比一下看输出差异。多线程的代码光看教程一万遍不如自己动手跑一遍跑的时候再把线程状态打印出来很多抽象的概念一下就通了。下一篇可以继续聊锁的进阶语义、线程池参数以及并发容器把这一篇打下的基础接着往上垒。

相关新闻

SpringBoot智慧就业平台开发实践与架构设计

SpringBoot智慧就业平台开发实践与架构设计

1. 项目背景与核心价值 高校毕业生就业信息管理一直是高校学生工作的重要环节。传统就业信息发布方式存在信息分散、更新滞后、匹配效率低等问题。这个基于SpringBoot的智慧就业服务平台,正是为了解决这些痛点而设计的。 我在实际开发过程中发现,一个高…

2026/10/14 14:19:30 阅读更多 →
燃气厂站视觉安全管控:工业级计算机视觉落地实践

燃气厂站视觉安全管控:工业级计算机视觉落地实践

1. 这不是PPT里的“智能监控”——而是真正扛过雷雨夜、扛住粉尘干扰、扛得住三年连续运行的视觉系统你可能在不少燃气厂站的汇报材料里见过这类标题:“基于AI的智能安全监管平台”。点开一看,多半是几帧干净实验室环境下的demo图:人站在围栏…

2026/10/14 14:19:30 阅读更多 →
燃气厂站计算机视觉落地:物理约束驱动的工业安全感知

燃气厂站计算机视觉落地:物理约束驱动的工业安全感知

1. 为什么燃气厂站成了计算机视觉落地的“硬骨头”?去年冬天,我在华北某地参与一个燃气调压站智能化改造项目,现场刚拍完一组红外热成像图,安全主管就指着屏幕说:“这台法兰接口温度比周边高8℃,但肉眼根本…

2026/10/14 14:19:30 阅读更多 →

最新新闻

快速阅读不靠眼快:筛选与理解的实用框架

快速阅读不靠眼快:筛选与理解的实用框架

经常有人问我:“你读书怎么那么快?是不是一目十行、走马观花?”说实话,我刚开始试水快速阅读的时候也踩过不少坑,最典型的表现是字都看完了,合上书一问三不知。后来我花了很长时间去拆解“快速阅读”和“快…

2026/10/14 18:20:44 阅读更多 →
存量市场服务升级:低风险高回报的商业模式

存量市场服务升级:低风险高回报的商业模式

1. 为什么说"稳妥生意"比创业更值得关注最近三年,我身边有37位朋友尝试创业,最终存活下来的只有3家。这个残酷的数字让我开始思考:对于大多数普通人来说,是否存在着比创业风险更低、回报更稳定的商业机会?经…

2026/10/14 18:20:44 阅读更多 →
Decepticon 实战手册:EtherNet/IP + CIP 协议攻击全流程(44818/2222 端口下的 PLC 侦察、标签读写与模式切换)

Decepticon 实战手册:EtherNet/IP + CIP 协议攻击全流程(44818/2222 端口下的 PLC 侦察、标签读写与模式切换)

【免费下载链接】Decepticon Autonomous Hacking Agent for Red Team 项目地址: https://gitcode.com/gh_mirrors/de/Decepticon 点击查看 免费下载 本指南基于 Decepticon 仓库中 enip-cip 技能文档 编写,系统讲解针对北美工业控制系统(ICS…

2026/10/14 18:20:44 阅读更多 →
中点画圆算法详解:光栅化生成完美圆的数学原理与代码实现

中点画圆算法详解:光栅化生成完美圆的数学原理与代码实现

圆的生成算法,是计算机图形学课程里最容易被低估的一个实验。很多同学看到“画圆”两个字,第一反应是直接调用窗口库里的画圆函数,几行代码就结束。但实验真正要你做的,是把它当成一道光栅化算法题:输入圆心坐标、半径…

2026/10/14 18:20:44 阅读更多 →
把“学术导航仪”装进书匠策AI:一篇期刊论文的“造路”逻辑

把“学术导航仪”装进书匠策AI:一篇期刊论文的“造路”逻辑

官网直达:www.shujiangce.com 微信公众号搜一搜:书匠策AI 写期刊论文最折磨人的,从来不是“写”这个动作本身。 是你盯着空白文档,知道要做文献综述,却不知道从哪篇开始;知道要有理论框架,却拿…

2026/10/14 18:20:44 阅读更多 →
插件加载失败排查:从生命周期到激活机制,一篇搞定

插件加载失败排查:从生命周期到激活机制,一篇搞定

先说一句,我带过好几个插件化改造的项目,也修过无数跟插件相关的启动报错,所以看到 "failed to load plugins web boot: 2 entries did not activate" 这种日志时,第一反应不是翻框架文档,而是看插件的激活方…

2026/10/14 18:19:43 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →