- 浏览: 248674 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
javatozhang:
讲解的的确不错。很实用。
Hibernate数据拦截与事件监听 -
sjx19871109:
更正一个地方:<event type="pos ...
Hibernate search -
xifan:
你好,楼主。
mutable="false 好像是 ...
Hibernate持久化对象生命周期 -
leo_cao:
很好,很实用
Hibernate数据拦截与事件监听 -
fehly:
47816778 写道你这样不会出现number 的精度问题吗 ...
Hibernate Annotations
线 程
线程是一个程序内部的顺序控制流
线程和进程
- 每个进程都有独立的代码和数据空间,进程切换的开销大
- 线程:轻量的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(pc),线程切换的开销小.
- 多进程:在操作系统中能同时运行多个任务(程序);
- 多线程:在同一应用程序中有多个顺序流同时执行.
线程的概念模型
- 虚拟的cpu,由java.lang.Thread类封装和虚拟;
- cpu所执行的代码,传递给Thread类对象;
- cpu所处理的数据,传递给Thread类对象
创建线程
java的线程是通过java.lang.Thread类实现的.
每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。
public class TestThread1 { public static void main(String args[]) { Runner1 r = new Runner1(); Thread t = new Thread(r); t.start(); } } class Runner1 implements Runnable { public void run() { for(int i=0; i<30; i++) { System.out.println("No. " + i); } } }
多线程
java中引入线程机制的目的在于实现多线程(Multi-Thread)
public class TestThread2 { public static void main(String args[]) { Runner2 r = new Runner2(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); } } class Runner2 implements Runnable { public void run() { for(int i=0; i<20; i++) { String s = Thread.currentThread().getName(); System.out.println(s + ": " + i); } } }
创建线程第二种方式
直接继承Thread类创建线程
public class TestThread3 { public static void main(String args[]){ Thread t = new Runner3(); t.start(); } } class Runner3 extends Thread { public void run() { for(int i=0; i<30; i++) { System.out.println("No. " + i); } } }
两种方式的比较
一.使用Runnable接口创建线程:
- 可以将cpu,代码和数据分开,形成清晰的模型;
- 线程体run()方法所在的类还可以从其他类继承一些有用的属性或方法;
- 并有利于保持程序风格的一致性.
二.直接继承Thread类创建线程:
- Thread子类无法再从其他类继承
- 编写简单,run()方法的当前对象就是线程对象,可直接操纵.
后台线程
相关基本概念:
- 后台处理(Background Processing)
- 后台线程(Background Thread/Daemon Thread)
- 用户线程(User Thread)
- 主线程(Main Thread)
- 子线程(Sub Thread)
Thread类提供的相关方法:
- public final boolean isDaemon()
- public final void setDaemon(Boolean on)
public class TestDaemonThread { public static void main(String args[]){ Thread t1 = new MyRunner(10); t1.setName("用户线程t1"); t1.start(); Thread t2 = new MyRunner(100); t2.setDaemon(true); t2.setName("后台线程t2"); t2.start(); for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName() + ": " + i); } System.out.println("主线程结束!"); } } class MyRunner extends Thread { private int n; public MyRunner(int n){ this.n = n; } public void run() { for(int i=0; i<n; i++) { System.out.println(this.getName() + ": " + i); } System.out.println(this.getName() + "结束!"); } }
线程的生命周期
- 新建状态
- 就绪状态
- 运行状态
- 阻塞状态
- 终止状态
线程优先级
线程的优先级用数字来表示,范围从1到10.
主线程的缺省优先级是5,子线程的优先级默认与其父线程相同.
Thread类提供的相关方法:
- public final int getPriority()
- public final void setPriority(int newPriority)
相关静态整型常量:
- Thread.MIN_PRIORITY=1
- Thread.MAX_PRIORITY=10
- Thread.NORM_PRIORITY=5
public class TestPriority { public static void main(String args[]){ System.out.println("线程名\t优先级"); Thread current = Thread.currentThread(); System.out.print(current.getName() + "\t"); System.out.println(current.getPriority()); Thread t1 = new Runner(); Thread t2 = new Runner(); Thread t3 = new Runner(); t1.setName("First"); t2.setName("Second"); t3.setName("Third"); t2.setPriority(Thread.MAX_PRIORITY); t3.setPriority(8); t1.start(); t2.start(); t3.start(); } } class Runner extends Thread { public void run() { System.out.print(this.getName() + "\t"); System.out.println(this.getPriority()); } }
线程串行化
在多线程程序中,如果在一个线程运行的过程中药用到另一个线程的运行结果,则可进行线程的串型化处理.
Thread类提供的相关方法:
- public final void join()
- public final void join(long millis)
- public final void join(long millis,int nanos)
public class TestJoin { public static void main(String args[]){ MyRunner r = new MyRunner(); Thread t = new Thread(r); t.start(); try{ t.join(); }catch(InterruptedException e){ e.printStackTrace(); } for(int i=0;i<50;i++){ System.out.println("主线程:" + i); } } } class MyRunner implements Runnable { public void run() { for(int i=0;i<50;i++) { System.out.println("SubThread: " + i); } } }
线程休眠
线程休眠——暂停执行当前运行中的线程,使之进入阻塞状态,待经过指定的"延迟时间"后再醒来并转入到就绪状态.
Thread类提供的相关方法:
- public static void sleep(long millis)
- public static void sleep(long millis,int nanos)
import java.awt.Color; import java.util.Calendar; import java.util.GregorianCalendar; import javax.swing.*; public class DigitalClock{ public static void main(String[] args){ JFrame jf = new JFrame("Clock"); JLabel clock = new JLabel("Clock"); clock.setHorizontalAlignment(JLabel.CENTER); jf.add(clock,"Center"); jf.setSize(140,80); jf.setLocation(500,300); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jf.setVisible(true); Thread t = new MyThread(clock); t.start(); } } class MyThread extends Thread{ private JLabel clock; public MyThread(JLabel clock){ this.clock = clock; } public void run(){ while(true){ clock.setText(this.getTime()); try{ Thread.sleep(1000); //this.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } } public String getTime(){ Calendar c = new GregorianCalendar(); String time = c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" + c.get(Calendar.DATE) + " " ; int h = c.get(Calendar.HOUR_OF_DAY); int m = c.get(Calendar.MINUTE); int s = c.get(Calendar.SECOND); String ph = h<10 ? "0":""; String pm = m<10 ? "0":""; String ps = s<10 ? "0":""; time += ph + h + ":" + pm + m + ":" + ps + s; return time; } }
线程让步
线程——让运行中的线程主动放弃当前获得的CPU处理机会,但不是该线程阻塞,而是使之转入就绪状态.
Thread类提供的相关方法:
- public static void yield()
import java.util.Date; public class TestYield{ public static void main(String[] args){ Thread t1 = new MyThread(false); Thread t2 = new MyThread(true); Thread t3 = new MyThread(false); t1.start(); t2.start(); t3.start(); } } class MyThread extends Thread{ private boolean flag; public MyThread(boolean flag){ this.flag = flag; } public void setFlag(boolean flag){ this.flag = flag; } public void run(){ long start = new Date().getTime(); for(int i=0;i<500;i++){ if(flag) Thread.yield(); System.out.print(this.getName() + ": " + i + "\t"); } long end = new Date().getTime(); System.out.println("\n" + this.getName() + "执行时间: " + (end - start) + "毫秒"); } }
线程挂起和恢复
线程挂起——暂时停止当前运行中的线程,使之转入阻塞状态,并且不会自动恢复运行.
线程恢复——使得一个已挂起的线程恢复运行.
Thread类提供的相关方法:
- public final void suspend()
- public final void resume()
利用线程挂起/恢复机制实现倒计时器
import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Date; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JButton; public class TestSuspend{ public static void main(String[] args){ JFrame jf = new JFrame("Timer"); JButton pause = new JButton("Pause"); JLabel clock = new JLabel("Timer"); clock.setBackground(Color.GREEN); clock.setOpaque(true); clock.setHorizontalAlignment(JLabel.CENTER); jf.add(clock,"Center"); jf.add(pause,"North"); jf.setSize(140,80); jf.setLocation(500,300); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jf.setVisible(true); MyThread mt = new MyThread(clock,10000); mt.start(); MyListener ml = new MyListener(clock,mt); pause.addActionListener(ml); } } class MyThread extends Thread{ private JLabel clock; private long time; private long end; public MyThread(JLabel clock,long time){ this.clock = clock; this.time = time; } public void init(){ long start = new Date().getTime(); end = start + time; } public void run(){ this.init(); while(true){ long now = new Date().getTime(); time = end - now; if(time > 0){ String s = this.convert(time); clock.setText(s); }else{ break; } try{ Thread.sleep(10); }catch(InterruptedException e){ e.printStackTrace(); } } clock.setText("时间到!"); clock.setBackground(Color.RED); } public String convert(long time){ long h = time / 3600000; long m = (time % 3600000) / 60000; long s = (time % 60000) / 1000; long ms = (time % 1000) / 10; String ph = h<10 ? "0":""; String pm = m<10 ? "0":""; String ps = s<10 ? "0":""; String pms = ms<10 ? "0":""; String txt = ph + h + ":" + pm + m + ":" + ps + s + "." + pms + ms; return txt; } } class MyListener implements ActionListener{ private JLabel clock; private MyThread mt; private boolean running= true; public MyListener(JLabel clock,MyThread mt){ this.clock = clock; this.mt = mt; } public void actionPerformed(ActionEvent e){ if(!mt.isAlive()) return; JButton jb = (JButton)(e.getSource()); if(running){ jb.setText("Replay"); clock.setBackground(Color.YELLOW); mt.suspend(); }else{ jb.setText("Pause"); clock.setBackground(Color.green); mt.init(); mt.resume(); } running = !running; } }
线程控制基本方法
isAllve() 判断线程是否还"活"着,即线程是否还未终止 getPriority() 获得线程的优先级数值 setPriority() 设置线程的优先级数值 sleep() 将当前线程睡眠指定毫秒数 join() 调用某线程的该方法,将当前线程与该线程"合并",即等待该线程结束,再恢复当前线程的运行. yield() 让出cpu,当前线程进入就绪队列等待调度 suspend()/resume() 挂起和恢复线程 wait() 当前线程进入对象的wait pool notify()和notifyAll() 唤醒对象的wait pool中的一个/所有等待线程
互斥锁
- 在java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性.
- 每个对象都对应于一个可称为"互斥锁"的标记,这个标记用来保证在任意时刻,只能有一个线程访问该对象.
- 关键字synchronized来与对象的互斥锁联系,当某个对象用synchronized修饰时,表明该对象在任意时刻只能由一个线程访问.
synchronized用法
用于方法声明中,标明整个方法为同步方法
public synchronized void push(char c){ data[idx] = c; idx++; }
public char pop(){ //其他代码 synchronized(this){ idx--; return data[idx]; } //其他代码 }
线程死锁
并发运行的多个线程间彼此等待,都无法运行的状态称为线程死锁.
public class TestDeadLock{ public static void main(String args[]){ StringBuffer sb = new StringBuffer("ABCD"); MyThread t = new MyThread(sb); t.start(); synchronized(sb){ try{ t.join(); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(sb); } System.out.println("Main thread is over!"); } } class MyThread extends Thread{ private StringBuffer sb; public MyThread(StringBuffer sb){ this.sb = sb; } public void run(){ synchronized(sb){ sb.reverse(); } System.out.println("Sub thread is over!"); } }
---------------------------------------------------------------------------------------------------------------------------------
public class TestDeadLock2{ public static void main(String args[]){ char[] a = {'A','B','C'}; char[] b = {'D','E','F'}; MyThread t1 = new MyThread(a,b); MyThread t2 = new MyThread(b,a); t1.start(); t2.start(); } } class MyThread extends Thread{ private char[] source; private char[] dest; public MyThread(char[] source,char[] dest){ this.source = source; this.dest = dest; } public void run(){ synchronized(source){ try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } synchronized(dest){ System.arraycopy(source,0,dest,0,source.length); System.out.println(dest); } } } }
线程同步通信
为避免死锁,在线程进入阻塞状态时应尽量释放其锁定的资源,以为其他的线程提供运行的机会.
相关方法:
- public final void wait()
- public final void notify()
- public final void notfyAll()
生产者——消费者问题
public class SyncStack{ //支持多线程同步操作的堆栈的实现 private int index = 0; private char []data = new char[6]; public synchronized void push(char c){ while(index == data.length){ try{ this.wait(); }catch(InterruptedException e){} } this.notify(); data[index] = c; index++; System.out.println("produced:"+c); } public synchronized char pop(){ while(index ==0){ try{ this.wait(); }catch(InterruptedException e){} } this.notify(); index--; System.out.println("消费:"+data[index]); return data[index]; } }
public class SyncTest{ public static void main(String args[]){ SyncStack stack = new SyncStack(); Runnable p=new Producer(stack); Runnable c = new Consumer(stack); Thread t1 = new Thread(p); Thread t2 = new Thread(c); t1.start(); t2.start(); } } class Producer implements Runnable{ SyncStack stack; public Producer(SyncStack s){ stack = s; } public void run(){ for(int i=0; i<20; i++){ char c =(char)(Math.random()*26+'A'); stack.push(c); try{ Thread.sleep((int)(Math.random()*300)); }catch(InterruptedException e){ } } } } class Consumer implements Runnable{ SyncStack stack; public Consumer(SyncStack s){ stack = s; } public void run(){ for(int i=0;i<20;i++){ char c = stack.pop(); try{ Thread.sleep((int)(Math.random()*500)); }catch(InterruptedException e){ } } } }
线程间数据传输
使用管道流实现线程间数据传输
import java.io.*; public class Test{ public static void main(String args[]){ PipedInputStream pin = new PipedInputStream(); PipedOutputStream pout = new PipedOutputStream(); try{ pin.connect(pout); }catch(IOException e){ e.printStackTrace(); } Thread t1 = new Sender(pout); Thread t2 = new Receiver(pin); t1.start(); t2.start(); } } class Sender extends Thread{ private DataOutputStream dos; public Sender(PipedOutputStream p){ dos = new DataOutputStream(p); } public void run(){ try{ dos.writeUTF("HelloWorld"); dos.close(); }catch(IOException e){ e.printStackTrace(); } } } class Receiver extends Thread{ private DataInputStream dis; public Receiver(PipedInputStream p){ dis = new DataInputStream(p); } public void run(){ try{ System.out.println(dis.readUTF()); dis.close(); }catch(IOException e){ e.printStackTrace(); } } }
类的同步性与线程安全
验证同步类的线程安全性
import java.util.Vector; public class Test{ public static void main(String args[]){ Vector<String> v = new Vector<String>(); v.addElement("Tom"); v.addElement("Billy"); v.addElement("Kessy"); v.addElement("Mr Brown"); v.addElement("Kity"); v.addElement("Johnson"); v.addElement("Nancy"); v.addElement("Scott"); v.addElement("Ruby"); MyThread1 mt1 = new MyThread1(v); MyThread2 mt2 = new MyThread2(v); mt1.start(); mt2.start(); } } class MyThread1 extends Thread{ private Vector<String> v; public MyThread1(Vector<String> v){ this.v = v; } public void run(){ synchronized(v){ int total = v.size(); for(int i=0;i<total;i++){ String s = v.elementAt(i); StringBuffer sb = new StringBuffer(s); s = sb.reverse().toString(); v.setElementAt(s,i); System.out.println(v.elementAt(i)); } } } } class MyThread2 extends Thread{ private Vector<String> v; public MyThread2(Vector<String> v){ this.v = v; } public void run(){ v.clear(); } }
定时器
使用定时器实现数字时钟功能
import javax.swing.JFrame; import javax.swing.JLabel; import java.util.Timer; import java.util.TimerTask; import java.util.Calendar; import java.util.GregorianCalendar; public class TestTimer{ public static void main(String args[]){ JFrame jf = new JFrame("Clock"); JLabel clock = new JLabel("Clock"); clock.setHorizontalAlignment(JLabel.CENTER); jf.add(clock,"Center"); jf.setSize(140,80); jf.setLocation(500,300); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jf.setVisible(true); Timer t = new Timer(); TimerTask tt = new MyTask(clock); t.schedule(tt,0,1000); } } class MyTask extends TimerTask{ private JLabel clock; public MyTask(JLabel clock){ this.clock = clock; } public void run(){ clock.setText(this.getTime()); } public String getTime(){ Calendar c = new GregorianCalendar(); String time = c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" + c.get(Calendar.DATE) + " " ; int h = c.get(Calendar.HOUR_OF_DAY); int m = c.get(Calendar.MINUTE); int s = c.get(Calendar.SECOND); String ph = h<10 ? "0":""; String pm = m<10 ? "0":""; String ps = s<10 ? "0":""; time += ph + h + ":" + pm + m + ":" + ps + s; return time; } }
发表评论
-
Json将对象转换成字符串
2010-11-26 22:41 10662最近用到Json传输对象交互,整理一个简单的方法. ... -
JDBC编程
2010-05-13 20:03 4122数据库简介 数据库(DB,Data Base) 数据库管理 ... -
应用程序国际化
2010-05-12 20:44 1515基本概念 国际化(Internationalization, ... -
网络编程
2010-05-09 16:46 1800计算机网络基础 什么是计算机网络 把分布在不同地理区域的计 ... -
泛 型
2010-05-05 12:42 1732什么是泛型 泛型(Gernerics)机制自java se ... -
Java I/O编程
2010-05-04 20:58 6872java i/o原理 基本概念: I/O(Input/O ... -
集合与映射
2010-05-02 20:22 2327集合框架概述 集合就是将若干用途,性质相同或相见的数组合 ... -
控制台应用程序设计
2010-04-30 16:24 1855命令行参数 在启动时java控制台应用程序,可以一次性地向 ... -
java常用类
2010-04-29 16:33 5011Object类 java.lang.Object类是所有ja ... -
异常的处理
2010-04-27 18:46 1958异常 异常(Exception)是程序运行过程中发生的事件 ... -
高级类特性
2010-04-26 21:42 997说了开始复习基础了, ... -
java.lang包错误概述
2010-04-15 20:07 2290接口 java.lang.Appendable可追加(app ... -
java对日期的操作技巧
2010-03-30 15:52 1444这篇文章是很早很早存机子上的...也是在哪里看到的然 ... -
MyEclipse6.5安装SVN插件的三种方法
2010-03-18 16:06 1588一、安装方法: 方 ... -
关于java打包问题
2010-03-09 20:25 23021、怎么把一个java文件打包到当前目录 javac ... -
关于MyEclipse/Eclipse汉化问题
2010-03-07 19:23 1274这个是关于MyEclipse/Eclips ... -
Could not find the main class. Program will exit
2010-03-06 21:07 11319虽然说 ...
相关推荐
在多线程编程中,"子线程更新主线程数据"是一个常见的需求,尤其是在UI界面交互和后台处理相结合的应用中。主线程通常负责用户界面的显示与交互,而子线程则用于执行耗时的任务,避免阻塞主线程,提供良好的用户体验...
在多线程编程中,尤其是使用VC++进行开发时,如何有效地从子线程更新主线程的数据是一个重要的问题。这涉及到线程间通信(Thread Communication)的概念,它确保了不同线程之间的协作和数据同步。在Windows环境中,...
Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码 22 如何从子线程更新主线程数据Visual C++源代码...
"QT子线程更新主线程"这个主题涉及到如何在后台线程(子线程)执行耗时操作,并将结果安全地传递到用户界面线程(主线程),以避免阻塞UI,保持其流畅性。 Qt库提供了QThread类来支持多线程编程。子线程通常用于...
本文将深入探讨如何在Android环境中实现两个子线程之间的通信。 首先,理解Android线程模型至关重要。主线程,也称为UI线程,负责处理用户界面的更新和事件响应。为了不阻塞主线程,我们通常会在子线程中执行耗时...
子线程任务发生异常,主线程事务如何回滚? 本文将详细探讨当子线程任务发生异常时,如何让主线程捕获到该异常并进行事务的回滚。下面将从多线程编程的基础知识、线程池的使用、异常捕获三个方面进行阐述。 一、多...
子线程与主线程之间的通信方式有很多种,如使用共享变量、wait/notify机制、Future和Callable接口等。而观察者模式(Observer Pattern)则是一种设计模式,它允许一个对象的状态变化自动通知其他依赖该对象的对象。...
在C# Winform应用开发中,主线程与子线程的协同工作是一项核心技能,尤其在处理耗时操作,如数据库查询、网络通信等时,更显得至关重要。本主题聚焦于如何利用“异步委托”在主线程中显示数据,同时在子线程中获取...
然而,当涉及到用户界面(UI)更新时,线程间通信(特别是从子线程到主线程)变得至关重要,因为Windows Forms和WPF等UI框架通常不是线程安全的。本实例将探讨如何在C#.NET中从子线程安全地更新主线程数据。 在...
在Android应用开发中,UI线程(也称为主线程)负责处理用户交互和绘制界面,而子线程通常用于执行耗时操作,如网络请求、数据处理等。由于Android系统的安全机制,直接在子线程中修改UI是不允许的,因此我们需要通过...
然而,由于GUI(图形用户界面)组件的设计原则,子线程不能直接修改主UI(用户界面)元素,因为这可能导致界面的不稳定性。为了解决这个问题,Qt提供了一种安全的方式来实现子线程与主线程之间的通信,确保UI的正确...
C#子线程刷新主线程示例源码 功能介绍: 使用线程操作 1、实时显示当前时间 2、输入加数和被加数,自动出现结果 技术特点: 使用了多线程实现了子线程刷新主线程 ,使用委托刷新主线程。 注意: 开发环境为...
在多线程编程中,子线程与主线程的交互是一个常见的需求,特别是在GUI应用程序中。主线程通常负责用户界面的更新和事件处理,而子线程则用于执行耗时的任务,以避免阻塞UI。本示例将深入探讨如何在Java或C#等支持多...
c#子线程如何读取及设置主线程ui的值,自己录的一个小视频,方便理解,比较菜鸟的方法,请勿喷!
在编程领域,尤其是在GUI(图形用户界面)应用开发中,"子线程创建界面组件"是一个重要的主题。这个话题涉及到多线程技术以及如何在非主线程中安全地构建和更新用户界面。以下是对这个主题的详细解释: 1. **线程与...
在QT中,主线程通常负责用户界面的更新和事件处理,而子线程则可以执行耗时的操作,如数据库查询、网络通信等,以避免阻塞主线程,保持UI的响应性。主线程被称为“GUI线程”,因为它维护着图形用户界面的事件循环。 ...
"Ios子线程渲染Opengl demo"是一个实例项目,展示了如何在iOS应用中将OpenGL渲染过程移到子线程,以避免阻塞主线程,提高用户体验。在iOS中,主线程主要负责处理用户交互和UI更新,因此保持主线程的流畅至关重要。当...
在Android开发中,多线程通信是一个至关重要的概念,尤其是主线程(UI线程)与子线程之间的交互。标题“子线程接收主线程发送的消息”涉及到的是Android中的Handler机制,这是一种处理线程间通信的方式。我们首先来...
"通过窗口传递让主线程触发FIRE事件(子线程不能触发)"这个话题聚焦于如何确保事件正确地在主线程中触发,因为某些操作必须在主线程中执行,比如更新UI。下面我们将深入探讨这一主题。 1. **线程安全与事件触发**...
在标题“Qt 串口,多线程(子线程处理串口信号)”中,我们关注的是如何在Qt环境中利用串口通信并结合多线程技术来优化程序性能。 1. **串口通信**: - **QSerialPort模块**:Qt提供QSerialPort类,用于处理串行...