Java多线程编程(初阶)

发布时间:2026/9/12 4:54:41

Java多线程编程(初阶) 引言关于线程的概念想必尊敬的读者已经有所了解不然也不会点开这篇博客所以基础概念等不再做多余赘述这篇博客仅仅是记录自己在学习多线程编程的途中的学习所得有写的不好的地方还望海涵。初识线程第一道多线程程序在Java中提供了Thread类来帮助我们实现多线程编程我们在学习之前可以先通过观察一段简单的多线程代码来看看多线程编程的运行效果class MyThread extends Thread{ Override public void run(){ while(true){ System.out.println(手动创建的线程在运行); } } } public class demo01{ public static void main(String[] args) { Thread t new MyThread(); t.start(); while(true){ System.out.println(主函数线程在运行); } } }如果你第一次见到它可能会觉得不可思议程序里明明有两个死循环一个在run里一个在main里按常理代码应该先卡在第一个while(true)里永远出不来才对。可运行之后控制台却疯狂地交替刷出两句话主函数线程在运行手动创建的线程在运行主函数线程在运行手动创建的线程在运行……就好像两个人同时抢着向你喊话互不相让那么恭喜你就在这一刻你亲手写出了自己的第一个多线程程序。这个开场之所以“神奇”全在于t.start()。它悄悄做了一件事让 Java 虚拟机在背后又开辟了一条新的执行路径也就是一个新的线程。新线程会去执行run方法里的死循环而原来的main线程呢根本没停继续往下执行自己的那个死循环。于是两个while(true)真的就在“同时”跑了——至少在宏观上它们交替执行谁也没有被谁堵死。这就是多线程编程带给我们的第一份礼物从顺序执行到并行运转。其实观察仔细并且认真思考的话还是会有一些疑问的我们明明把要运行的程序是封装在MyThread类的run方法里的那为什么在main里面要通过start方法去运行呢为了弄懂二者的区别我们可以通过对比运行的结果来观察差异class MyThread extends Thread{ Override public void run(){ while(true){ System.out.println(手动创建的线程在运行); } } } public class demo02{ public static void main(String[] args) { Thread t new MyThread(); t.run(); while(true){ System.out.println(主函数线程在运行); } } }输出结果如下手动创建的线程在运行手动创建的线程在运行手动创建的线程在运行手动创建的线程在运行......可以看出如果是执行run方法的话主函数启动后会进入run方法然后一直运行run方法里面的死循环没有运行属于main里面的死循环这也违背了我们多线程程序并发运行的初衷在直接调用run方法的时候其实就和普通的调用类的方法没有区别我们的程序会老老实实的运行这个方法里面的内容直到这个方法运行结束才会退出在这个过程中没有任何新的线程产生多线程编程更是无从谈起。那么我来看看start为什么能实现多线程运行。在我们调用start的时候JVM会干这两件事1.JVM会调用操作系统的API在操作系统中创建一个新的线程并添加进线程运行列表2.新线程自动去调用这个对象的run方法于是原线程如 main 线程在 start() 返回后立刻继续往下执行新线程则并发地跑 run() 里的代码。两个 while(true) 就这样被分配到了两条独立的线程上宏观上同时运行实现了我们多线程运行的目的。Thread的多种初始化方式1.继承Thread类其实这种初始化方法就是我们在第一道多线程程序里的方法我们通过继承Thread类并重写父类的run方法来运行自己想要运行的程序从而实现多线程编程class MyThread extends Thread{ Override public void run(){ //新建线程中的程序 } } public class demo03{ public static void main(String[] args) { Thread t new MyThread(); t.start(); .... //main里面的代码 } }2.实现Runnable接口传参除了直接继承Thread类,我们还可以通过实现Runnable接口然后创建一个对应的对象传参给一个普通的Thread类的方式来实现一个线程的创建。用实现Runnable接口的方法创建线程可以解耦合提升代码的效率。class MyRunnable implements Runnable{ Override public void run(){ //...... } } public class demo04 { public static void main(String[] args) { MyRunnable r new MyRunnable(); Thread t new Thread(r); t.start();//开始执行t线程中重写的run方法中的代码 //.......main函数中的代码 } }3.匿名内部类初始化Thread如果仔细观察上面的两种初始化方式我们可以发现有一个共同点它们的核心都是重写run函数那么我们可以使用匿名内部类的方式初始化大大减少代码的篇幅。public class demo05 { public static void main(String[] args){ Thread t new Thread(){ Override public void run(){ //...... } };//采用匿名内部类的方式重写run方法 t.start(); //...... } }4.匿名内部类初始化Runnable接口传参初始化Thread和第3种初始化方式同理我们也可以采用匿名内部类的方式实现Runnable接口传参进行初始化。public class demo06 { public static void main(String[] args) { Thread t new Thread(new Runnable() { Override public void run() { //...... } }); t.start(); } }5.Lambda表达式初始化Thread既然匿名内部类可以初始化Thread匿名我们可以用Lambda表达式来进一步降低代码的复杂度先用lambda表达式实现一个Runnable再把Runnable传给Thread进行初始化。public class demo07 { static void main(String[] args) { Thread t new Thread(()-{ //...... }); t.start(); //...... } }6.Lambda表达式单独实现Runnable传入如果想提高代码的复用性我们也可以先单独实现一个Runnable然后再把实现好的Runnable传入Thread进行初始化。public class demo08 { static void main(String[] args) { Runnable r ()-{ //...... }; Thread t1 new Thread(r); Thread t2 new Thread(r); t1.start(); t2.start();//其它Thread对象也可以复用已经实现好的Runnable //...... } }Thread的其它参数的初始化上面的6种初始化方式主要是讲如何创建一个线程Thread其实支持给线程进行命名在创建Thread对象的时候我们就可以通过传参的方式对创建的Thread对象进行命名。public class demo09 { static void main(String[] args) { Thread t1 new Thread(()-{ while(true){} }); Thread t2 new Thread(()-{ while(true){} }); Thread t3 new Thread(()-{ while(true){} }); Thread t4 new Thread(()-{ while(true){} }); Thread t5 new Thread(()-{ while(true){} }); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }在上面这组代码中我创建了5个未命名的线程并启动在Java自带的监视窗口中下图我们可以看到系统会从Thread-0开始默认命名在多线程的程序中我们如果想监视线程的运行情况这样肯定是不方便的所以有了可以进行命名的初始化方式。Thread的传参有以下几种Thread() //创建线程对象Thread(Runnnable r) //使用Runnable对象创建线程对象Thread(String name) //创建线程对象并命名Thread(Runnable r,String name) // 使用Runnable对象创建线程对象并命名我们这里以第四种为例演示一下效果public class demo10 { static void main(String[] args) { Thread t1 new Thread(()-{ while(true){} },运行t1线程); Thread t2 new Thread(()-{ while(true){} },运行t2线程); Thread t3 new Thread(()-{ while(true){} },运行t3线程); Thread t4 new Thread(()-{ while(true){} },运行t4线程); Thread t5 new Thread(()-{ while(true){} },运行t5线程); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }在线程运行的监视窗口可以看到原来的默认命名变成了我们自己的命名在多线程程序中我们可以通过描述该线程的作用进行命名来更好的了解程序的运行。多线程程序的演示sleep在下面这段代码中我们从运行结果可以看到多线程程序在运行期间每个线程的运行时间是随机的public class demo11 { static void main(String[] args) { Thread t new Thread(()-{ while(true){ System.out.println(t线程在运行); } }); t.start(); while(true){ System.out.println(main方法的线程在运行); } } }运行结果截图我们可以通过调用Thread的静态方法sleep并设置时间来人为控制一下线程在CPU上运行的时间public class demo12 { static void main(String[] args) { Thread t new Thread(()-{ while(true){ System.out.println(t线程在运行); try { Thread.sleep(1000);//这里将时间设置成1000毫秒 } catch (InterruptedException e) { throw new RuntimeException(e); } } }); t.start(); while(true){ System.out.println(main方法的线程在运行); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }运行结果截图关于调用sleep方法的抛出异常的补充说明可以看到在上述代码中如果不对调用了的sleep方法进行异常处理代码是会报错的但其实在重写的run方法里和main方法里的处理异常的方式页不同我们来看看区别可以看到main方法中的sleep的异常处理是有两种方法的一种是try-catch捕获还有一种是在main方法前用throws声明但是在重写的run方法里只支持try-catch捕获却没有支持throws声明这是为什么呢我可以尝试着都使用throws声明看看会发生什么可以看到同样是使用throws声明main方法那里是正常的但是run方法却报错了我们来看看报错原因可以看到IDEA告诉我们我们重写的run方法是继承自父类Thread的run方法而Thread中的run方法并没有抛出InterruptedException这个异常所以子类也不能抛出因为子类如果抛出异常而父类没有抛出那么子类的run的方法签名和父类的run方法签名不一致就不构成子类对父类的方法重写了所以继承了Thread的子类中run方法使用sleep方法只能使用try-catch的方式处理异常。多个线程运行效果演示在多线程运行程序中除了线程占据CPU的时长是随机的CPU调度线程的次序在不做设计的情况下也是随机的我们可以通过下面这组代码的运行结果来观察。public class demo13 { static void main(String[] args) { Thread t1 new Thread(()-{ while(true){ System.out.println(t1线程在运行); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); Thread t2 new Thread(()-{ while(true){ System.out.println(t2线程在运行); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); Thread t3 new Thread(()-{ while(true){ System.out.println(t3线程在运行); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); Thread t4 new Thread(()-{ while(true){ System.out.println(t4线程在运行); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); t1.start(); t2.start(); t3.start(); t4.start(); while(true){ System.out.println(main线程在运行); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }运行结果截图Thread的常见属性1.是否后台线程我们先了解什么叫后台线程什么叫前台线程什么叫后台线程。在学习多线程程序以前我们总是认为main方法执行完毕之后程序就运行结束了但学习了多线程编程之后我们会发现完全不是这么回事比如下面这段代码就可以看出main方法的执行完毕并不等于程序运行的结束public class test { private static Thread THread; public static void main(String[] args) throws InterruptedException { Thread t new Thread(()-{ for(int i0;i5;i){ System.out.println(hello thread); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } System.out.println(t 线程运行结束); }); t.start(); Thread.sleep(1000); System.out.println(main 线程运行结束); } }运行结果如下可以看出main线程里的代码运行结束后t线程的代码仍在运行t线程运行结束后程序才完全结束由此可以看出程序的结束与否不取决于main方法里所有代码执行完毕。实际上程序的结束与否取决于进程中是否还存在前台线程。我们默认创建的线程都是前台线程而JVM有一条铁律只要还有任何一个前台线程没有结束整个进程就不会退出JVM 会一直等它。所以main方法中的代码执行结束后程序仍没有停止而是把同样是前台线程的t线程也运行结束才结束。而后台线程也被称为“守护线程”它的职责是在后台默默提供一些辅助服务比如垃圾回收、缓存清理等如下图中除了我们创建的t线程(Thread-0)和main线程外还有很多其它的线程这些都是自动创建的后台线程。JVM 不会关心后台线程有没有执行完当前台线程全部结束时JVM 会直接退出并且强制终止所有还在运行的后台线程。我们可以调用setDaemon(true)这个方法把前台线程设置为后台线程注意这个方法必须在调用start方法前调用不然会抛出IllegalThreadStateException。我们通过这个方法来看看前后台线程的性质public class test { private static Thread THread; public static void main(String[] args) throws InterruptedException { Thread t new Thread(()-{ for(int i0;i5;i){ System.out.println(hello thread); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } System.out.println(t线程运行结束); }); t.setDaemon(true); t.start(); System.out.println(main线程运行结束); } }运行结果如下图可以看到本该输出5次的hello thread由于被设置成了后台线程在main方法里的代码被执行完后随着main线程的结束程序里的所有前台线程都结束了身为后台线程的t线程也被强制终止了没有被执行完。而想要知道一个线程是否是后台线程可以用isDaemon()这个方法其返回类型是booleanpublic class test { public static void main(String[] args) throws InterruptedException { Thread t new Thread(); System.out.println(t.isDaemon()); // false默认是前台线程 t.setDaemon(true); System.out.println(t.isDaemon());// true现在变成后台线程了 } }运行结果如下图2.线程名称在线程初始化的时候我们提到了线程在初始化的时候可以指定命名未指定的时候系统也会进行默认命名我们可以用getName()方法来获取线程的名字public class test { public static void main(String[] args) throws InterruptedException { Thread t1 new Thread();//系统默认命名 Thread t2 new Thread(自命名线程);//自己命名的线程 System.out.println(t1.getName()); System.out.println(t2.getName()); } }线程的各种属性以及接口方法属性获取方法说明线程IDlong getId()线程的唯一标识符由 JVM 自动分配从 1 开始递增线程终止后 ID 不会被重用。线程名称String getName()线程的名字可在创建时通过构造函数指定也可通过setName(String)修改。默认名称如Thread-0。优先级int getPriority()线程调度优先级范围是Thread.MIN_PRIORITY(1)~Thread.MAX_PRIORITY(10)默认通常为Thread.NORM_PRIORITY(5)。优先级高只是“建议”调度器多分配时间片不保证一定优先执行。线程状态Thread.State getState()返回当前线程的状态值为枚举NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED。用于判断线程的生命周期阶段。是否存活boolean isAlive()线程已启动且尚未终止时返回true。即从start()调用后到run()结束之间为存活状态。是否守护线程boolean isDaemon()返回线程是前台线程false还是后台守护线程true。可通过setDaemon(true)设置但必须在start()之前调用。是否被中断boolean isInterrupted()检查该线程的中断标志位是否为true不清除标志位。常用于循环条件判断线程是否被请求停止。线程组ThreadGroup getThreadGroup()返回该线程所属的线程组常用于批量管理线程。默认情况下新建线程属于创建它的线程的线程组。中断一个线程在讲完线程的创建、启动和基本属性后我们终于要面对一个关键问题线程不可能永远跑下去我们该如何让它停下来如果是单线程程序代码顺序执行完自然就结束了。但多线程里一个线程往往在循环里干活或者正睡着觉等待唤醒。强行把它“杀”掉不仅粗暴还可能让共享资源处于一团乱麻的状态。所以Java 选择了一种更优雅、也更符合程序员思维的方式——中断机制。我们有两种方式来中断线程在讲Java的interrupt()方法之前我们可以先了解共享标记的方式。1.通过共享标记进行沟通我们可以通过设置一个全局变量作为共享标记通过这个标记来控制线程的运行情况public class test { private static boolean running true; public static void main(String[] args) { Thread t new Thread(()-{ while(running){ System.out.println(hello thread); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } System.out.println(t线程退出); }); t.start(); Scanner sc new Scanner(System.in); System.out.println(请输入整数0表示让线程T终止); int n sc.nextInt(); if(n0){ running false; } } }在上面这段代码中我们设置了一个boolean类型的全局变量running来控制线程的运行当我们输入0的时候running会变成false重写的run方法里的while循环结束run方法中的代码执行完毕进而控制我们线程运行的中断。但是上述方法不是真正意义上的中断线程本质上仍然是线程运行的“结束”而不是中断比如如果是下面这样我们把每次println后的sleep时间设置的很长public class test { private static boolean running true; public static void main(String[] args) { Thread t new Thread(()-{ while(running){ System.out.println(hello thread); try { Thread.sleep(100_000); } catch (InterruptedException e) { throw new RuntimeException(e); } } System.out.println(t线程退出); }); t.start(); Scanner sc new Scanner(System.in); System.out.println(请输入整数0表示让线程T终止); int n sc.nextInt(); if(n0){ running false; } } }执行完sleep()后线程会进入阻塞状态即使我们输入了0该线程也会等sleep()中的时间结束后才会进入到while循环条件的判断并结束该循环进而结束线程而不是我们想要的立刻中断这个线程想要真正的中断一个线程我们还是要依靠Java的interrupt()方法。2.调用interrupt()方法我们可以通过的java的interrupt()方法来中断一个线程在重写的run方法的while里我们就可以先通过当前线程后使用isInterrupt()方法来判断该线程是否处于中断状态来作为循环的判断条件public class test { public static boolean running true; public static void main(String[] args){ Thread t new Thread(()-{ Thread cur Thread.currentThread();//获取当前线程 while(!cur.isInterrupted()){ System.out.println(t线程正在运行); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); t.start(); Scanner in new Scanner(System.in); int num in.nextInt(); System.out.println(输入0终止线程); if(num 0){ t.interrupt(); } } }相较于上一种方法即使线程在调用sleep()时处于阻塞状态这时候给它发中断信号Java 也会强行把线程从阻塞中唤醒并且抛出一个InterruptException。补充知识点基础语法相关running能不能是局部变量在中断线程的第一种方法中我们把running设置成了全局的静态变量不妨设置成局部变量再试试效果如图所示当我们把共享标记running设置成全局变量的时候线程t的Lambda表达式内部报错了我们可以先看一下IDEA给出的报错原因在报错提示中说了lambda表达式中捕获的变量必须是final或者事实final事实final是指这个变量没有被final修饰但是也没有修改在我们上述代码中running既不是final没有final修饰也不是事实final后续在main方法的if判断里面有被修改,不符合lambda的变量捕获的要求所以没法通过编译。那为什么这里的变量捕获要求变量必须是final或者事实final呢试想一下如果lambda表达式中使用的变量在lambda表达式执行之前就被main方法释放掉了那还怎么访问呢所以java中的变量捕获事实上是把使用的变量的值“拷贝”了一份那么就有了新问题这个值是拷贝来的如果这个变量后续的值被修改了由于是在lambda外部所以lambda内部无法同步更新修改就会导致变量的值不对等所以lambda在变量捕获的时候会要求捕获的变量是final或者事实final。其实如果仔细的话这时候就会发现一个隐藏的新问题了我最开始设置的running也不是final或者事实final那为什么可以正常运行呢这就涉及到lambda对静态变量的捕获了刚刚提到lambda捕获局部变量时是“拷贝”它的值但是lambda在捕获静态变量时获取的是静态变量的内存引用地址它每次执行都会去主内存中读取当前最新的值所以编译器不要求静态变量是不可变的。
延伸阅读

更多相关文章

2026/9/11 22:26:34

MRAM存储器使用方法(如何使用MRAM提高边缘计算)

在边缘计算高速发展的当下,终端设备对存储器件的延迟、功耗、稳定性与耐用性提出了严苛要求,传统存储方案已难以适配场景需求。MRAM存储器作为新一代非易失性磁性随机存取存储器件,凭借独特的物理存储架构,可实现全域随机读写操作…

2026/9/10 16:05:04

KeyStone I DSP硬件设计实战:从休眠模式到PCB布局的电源管理优化

1. 项目概述:从功耗焦虑到设计实践在嵌入式系统,尤其是高性能数字信号处理器的硬件设计领域,我从业十几年,最常被问到也最让工程师头疼的问题之一,就是如何平衡“性能”与“功耗”。一块板子跑起来容易,但要…

2026/9/12 22:46:11

脏纸编码与THP预编码:MU-MIMO非线性预编码的Matlab实现与仿真

简介:面向无线通信与信号处理方向的科研人员、研究生及高年级本科生,这份基于MATLAB的编码仿真资料聚焦脏纸编码(DPC)与Tomlinson-Harashima预编码(THP)的场景化实现。资源包含2个.m脚本,压缩包…

2026/9/12 22:46:11

霍夫圆变换实战:Python+OpenCV虹膜内外圆检测

简介:面向虹膜图像内外圆检测场景,这份资源是一套基于Python与OpenCV的完整实现,适合计算机视觉初学者、生物识别方向学生及需要快速上手霍夫圆变换的开发者。压缩包共9个文件,包含1个可直接运行的Python脚本和8张JPG图像&#xf…

2026/9/12 22:46:11

DE优化BP神经网络:Matlab实现与参数调优

简介:面向Matlab开发者和机器学习初学者的DE-BP差分算法优化BP神经网络分类预测资源,专注解决分类预测中传统BP网络易陷入局部最优、参数难调的问题。整个资源包共11个文件,包含5个Matlab脚本和4个mat数据集,脚本覆盖差分进化算法…

2026/9/12 22:46:11

全平台免费抓包工具盘点:从原理到实操一次讲透

做接口调试这些年,我几乎每天都要打开抓包工具看看请求到底长什么样。经常有朋友问我:免费的抓包工具到底选哪个?网上搜出来的答案七零八落,不是只讲Wireshark,就是只讲Fiddler,看完还是不知道怎么下手。正…

2026/9/12 22:46:11

清标慧审实测:28家标书人工与工具对比,316条漏检背后的真相

2026年1月初,我接到东部新区市政道路及配套管网工程的清标任务。一标段招标控制价9.76亿元,28家投标人,每家标书连报价带技术标平均300页出头,全部加起来将近8500页。甲方给了5个工作日,要一份能支撑评标委员会使用的清…

2026/9/12 2:05:33

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/12 3:55:12

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/12 10:09:03

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/12 0:04:17

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现

简介:本资源是一份面向智能优化算法研究者与MATLAB初学者的仿生智能算法实践代码包,聚焦于长鼻浣熊优化算法(COA)的多策略改进与性能验证。针对传统COA易陷局部最优、收敛精度不足等问题,作者融合Circle映射初始化提升…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/12 6:37:43

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码