news 2026/7/23 19:54:12

初识线程:带你理解程序运行的基本流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
初识线程:带你理解程序运行的基本流程

一、基本概念

开发程序是为了解决问题

1.程序

一个存在磁盘中的程序(一份文件 代码文件+数据文件)不能解决问题

2.进程

正在运行中的程序 代码和数据 都在内存中

  • 可以解决问题:通过(代码-计算机指令)调度计算机资源(CPU缓存、RAM磁盘、IOSystem IO操作系统)来解决问题
  • 当一个计算机需要同时运行多个进程时,需要操作系统来帮忙
  • 当一个程序需要同时进行多个任务时,需要使用线程
  • 操作系统分配资源的最小单元

3.线程

  • 一个进程的组成部分,任何一个进程都至少有一个线程
  • 进程也需要操作系统帮忙管理线程
  • CPU分配执行任务的最小单元 就是线程
  • 进程使用多线程的优势是:可以共享数据

二、线程

1.Java中实现线程的方式

(1)继承父类(Thread)

  • 继承:public class MyThread extends Thread{ }
  • 重写方法run: public void run( ){ }
  • 将需要独立放在线程中执行的代码写在run方法中
  • 启动线程:使用MyThread类 创建对象并且调用start方法(不可调用run)

eg.创建继承 Thread 的类

/** * 继承 Thread 类的自定义线程类 */ public class MyThread extends Thread { private String threadName; // 构造方法,可以传入线程名称 public MyThread(String name) { this.threadName = name; } /** * 重写 run 方法,包含线程要执行的代码 * 注意:run() 方法是线程的入口点 */ @Override public void run() { System.out.println(threadName + " 线程开始执行..."); try { // 模拟耗时操作 for (int i = 1; i <= 5; i++) { System.out.println(threadName + " - 执行第 " + i + " 次任务"); // 休眠1秒,模拟任务执行时间 Thread.sleep(1000); // 可以调用其他方法 doSomething(i); } } catch (InterruptedException e) { System.out.println(threadName + " 被中断"); } System.out.println(threadName + " 线程执行完毕"); } /** * 线程中可以执行的其他方法 */ private void doSomething(int count) { System.out.println(threadName + " - 正在处理第" + count + "个数据"); } }

使用 MyThread 创建线程并启动

/** * 主类,演示如何使用 MyThread 创建和启动线程 */ public class ThreadExample { public static void main(String[] args) { System.out.println("主线程开始执行..."); // 示例1: 创建单个线程 System.out.println("=== 示例1: 创建单个线程 ==="); // 第一步: 创建 MyThread 对象 MyThread thread1 = new MyThread("线程A"); // 第二步: 调用 start() 方法启动线程 thread1.start(); // 注意:不要调用 run() 方法 // 验证直接调用 run() 和调用 start() 的区别 System.out.println("\n=== 测试直接调用 run() 方法 ==="); MyThread testThread = new MyThread("测试线程"); // 直接调用 run() 方法(错误示例) System.out.println("直接调用 run() 方法:"); testThread.run(); // 这会在当前线程(主线程)中执行,不会创建新线程 System.out.println("\n=== 测试调用 start() 方法 ==="); MyThread testThread2 = new MyThread("正确线程"); testThread2.start(); // 正确:会在新线程中执行 // 主线程继续执行其他任务 for (int i = 0; i < 3; i++) { System.out.println("主线程执行任务: " + i); try { Thread.sleep(800); // 主线程休眠 } catch (InterruptedException e) { e.printStackTrace(); } } // 示例2: 创建多个线程 System.out.println("\n=== 示例2: 创建多个线程 ==="); MyThread thread2 = new MyThread("线程B"); MyThread thread3 = new MyThread("线程C"); // 启动多个线程 thread2.start(); thread3.start(); // 等待所有线程执行完毕 try { thread1.join(); // 等待线程1结束 thread2.join(); // 等待线程2结束 thread3.join(); // 等待线程3结束 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("所有线程执行完毕,主线程结束"); } }

(2)实现接口(Runnable)

  • 实现接口:public class MyRun implements Runnable{ }
  • 重写run方法
  • 实现线程中的代码
  • 使用MyRun创建一个对象,将这个对象放在一个Thread类对象的构造方法中,使用Thread对象start方法

eg.创建实现 Runnable 接口的类

/** * 实现 Runnable 接口的类 */ public class MyRun implements Runnable { private String threadName; // 构造方法,可以传入线程名称 public MyRun(String name) { this.threadName = name; } /** * 重写 run 方法,包含线程要执行的代码 */ @Override public void run() { try { for (int i = 1; i <= 5; i++) { // 模拟耗时操作 Thread.sleep(1000); // 休眠1秒 // 打印当前线程信息 System.out.println(threadName + " - 正在执行: " + i); // 可以在run方法中调用其他方法 doSomething(i); } } catch (InterruptedException e) { System.out.println(threadName + " 被中断"); } System.out.println(threadName + " 执行完毕"); } /** * 线程中可以执行的其他方法 */ private void doSomething(int count) { System.out.println(threadName + " - 执行第" + count + "次操作"); } }

使用 MyRun 创建线程并启动

/** * 主类,演示如何使用 MyRun 创建和启动线程 */ public class ThreadExample { public static void main(String[] args) { System.out.println("主线程开始执行..."); // 示例1: 创建单个线程 System.out.println("=== 示例1: 创建单个线程 ==="); // 第一步: 创建 MyRun 对象(实现了Runnable接口) MyRun myRun1 = new MyRun("线程A"); // 第二步: 将 MyRun 对象作为参数创建 Thread 对象 Thread thread1 = new Thread(myRun1); // 第三步: 调用 Thread 对象的 start() 方法启动线程 thread1.start(); // 主线程继续执行其他任务 for (int i = 0; i < 3; i++) { System.out.println("主线程执行任务: " + i); try { Thread.sleep(800); // 主线程休眠 } catch (InterruptedException e) { e.printStackTrace(); } } // 示例2: 创建多个线程 System.out.println("\n=== 示例2: 创建多个线程 ==="); MyRun myRun2 = new MyRun("线程B"); MyRun myRun3 = new MyRun("线程C"); Thread thread2 = new Thread(myRun2); Thread thread3 = new Thread(myRun3); // 启动多个线程 thread2.start(); thread3.start(); // 等待所有线程执行完毕 try { thread1.join(); // 等待线程1结束 thread2.join(); // 等待线程2结束 thread3.join(); // 等待线程3结束 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("所有线程执行完毕,主线程结束"); } }

(3)实现Callable接口(最新,复杂)

目前所学知识无法实现,后续学到会补充

tips.同一个thread对象不可调用多次start函数(同一个线程在一个生命周期内(创建-运行-销毁)只能启动一次)

但同一个runnable接口类可以同时被多个thread运行

2.继承父类和实现接口两种创建线程的方式区别?

(1)继承机制

继承 Thread 类

// 继承 Thread 类 public class MyThread extends Thread { @Override public void run() { // 线程代码 } } // 使用 MyThread thread = new MyThread(); thread.start();

实现 Runnable 接口

// 实现 Runnable 接口 public class MyRunnable implements Runnable { @Override public void run() { // 线程代码 } } // 使用 MyRunnable runnable = new MyRunnable(); Thread thread = new Thread(runnable); thread.start();

(2)核心区别对比表

对比点继承 Thread 类实现 Runnable 接口
继承限制占用继承位置(Java单继承)不占用继承位置,可以继承其他类
代码结构线程和任务耦合在一起线程和任务分离,更清晰
资源共享相对复杂方便共享资源(同一个Runnable对象)
扩展性较差更好,更灵活
面向对象不符合"组合优于继承"原则符合面向对象设计原则

(3)实际开发中的选择标准

选择继承 Thread 类的情况:
  1. 需要重写 Thread 类的其他方法(如 interrupt())

  2. 简单的单线程任务

  3. 不需要共享资源

  4. 学习或演示目的

选择实现 Runnable 接口的情况:
  1. 需要继承其他类(Java单继承限制)

  2. 需要多个线程共享资源

  3. 使用线程池管理线程

  4. 代码需要更好的可扩展性

  5. 大多数实际项目场景

在绝大多数情况下,应该优先使用实现 Runnable 接口的方式创建线程。只有在需要重写 Thread 类的特定方法时,才考虑继承 Thread 类。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 23:30:41

洛谷 P9100 [PA 2020] Miny 题解

这道题难点在于状态设计。考虑线性 DP&#xff0c;设 dpidp_idpi​ 为仅考虑前 iii 个地雷且钦定第 iii 个不引爆的方案数。这样设计的好处在于 iii 前面的地雷一定不会引爆 iii 后面的&#xff0c;从而满足无后效性。 注意需要在左右无穷远处各添加一个爆炸半径无穷大的哨兵地…

作者头像 李华
网站建设 2026/7/21 15:40:32

从零开始学大模型核心:向量嵌入技术完全指南

文章全面介绍了向量嵌入技术在大模型中的应用&#xff0c;包括词嵌入、文档嵌入、多模态嵌入等多种类型&#xff0c;以及向量索引、存储优化和相似度计算等关键技术。文章详细阐述了嵌入与向量数据库的协同关系&#xff0c;以及在大规模语义搜索、推荐系统、异常检测和RAG等场景…

作者头像 李华
网站建设 2026/7/22 17:32:31

双非二程序员的大模型逆袭之路:RAG与Agent技术学习指南

本文探讨双非二本科生在大模型应用开发领域的就业前景&#xff0c;指出尽管学历存在挑战&#xff0c;但行业对RAG和Agent技术人才需求旺盛&#xff0c;更看重实际技术能力而非学历。文章分析了企业招聘要求、薪资前景&#xff0c;并提供了系统学习路径&#xff0c;包括Python编…

作者头像 李华
网站建设 2026/7/22 15:53:28

21点,如何计算胜率高达75%

算法原理低牌&#xff08;2-6&#xff09;&#xff1a;1分低牌&#xff08;2-6&#xff09;在21点中通常对玩家有利&#xff0c;因为它们更可能帮助玩家接近21点&#xff08;如16218&#xff0c;16319等&#xff09;&#xff0c;而不会轻易导致爆牌。因此&#xff0c;当低牌被打…

作者头像 李华
网站建设 2026/7/23 1:06:54

基于STM32单片机智能药盒 定时定量提醒 GSM短信 蜂鸣器提醒

目录硬件组成功能实现软件设计应用场景扩展功能建议源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;硬件组成 STM32单片机&#xff1a;作为主控芯片&#xff0c;负责协调各模块工作&#xff0c;处理定时、定量逻辑及通信功能。GSM模块&…

作者头像 李华