尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

【Java 课程作业】继承 Thread 类与实现 Runnable 接口创建线程的区别详解

【Java 课程作业】继承 Thread 类与实现 Runnable 接口创建线程的区别详解
📅 发布时间:2026/6/29 18:40:40

本文是 Java 面向对象程序设计课程的课后作业,详细讲解 Java 中两种最基础的线程创建方式:继承 Thread 类与实现 Runnable 接口。通过代码示例、经典售票案例和多维度对比,深入分析两者的本质区别、各自的优缺点以及实际开发中的选择原则。

文章目录

    • 一、Java 创建线程的两种基础方式
    • 二、两种方式的代码实现
      • 2.1 方式一:继承 Thread 类
      • 2.2 方式二:实现 Runnable 接口
    • 三、核心区别多维度对比
      • 3.1 对比总表
      • 3.2 详细解读
        • 1. 单继承限制(最本质区别)
        • 2. 资源共享能力
          • ❌ 继承 Thread 实现(需要用静态变量共享)
          • ✅ 实现 Runnable(天然共享)
        • 3. 代码解耦与复用
        • 4. 与线程池的兼容性
    • 四、开发中如何选择?
      • 推荐原则
      • 行业共识
    • 五、学习总结

一、Java 创建线程的两种基础方式

在 Java 中,创建线程最常用的有两种方式:

  1. 继承java.lang.Thread类,重写run()方法
  2. 实现java.lang.Runnable接口,实现run()方法,再将其作为参数传给 Thread 对象

很多初学者会疑惑:两种方式都能创建线程,它们到底有什么区别?为什么老师总说推荐使用Runnable接口?下面我们通过代码和案例逐一分析。


二、两种方式的代码实现

2.1 方式一:继承 Thread 类

实现步骤:

  1. 定义一个类继承Thread类
  2. 重写run()方法,编写线程执行的任务逻辑
  3. 创建该子类的实例对象
  4. 调用start()方法启动线程
/** * 方式一:继承Thread类创建线程 */publicclassMyThreadextendsThread{// 构造方法:设置线程名publicMyThread(Stringname){super(name);}// 重写run方法,编写线程任务@Overridepublicvoidrun(){for(inti=0;i<5;i++){System.out.println(Thread.currentThread().getName()+" 执行:"+i);try{// 模拟线程执行耗时Thread.sleep(200);}catch(InterruptedExceptione){e.printStackTrace();}}}// 测试publicstaticvoidmain(String[]args){// 创建两个线程对象MyThreadt1=newMyThread("线程A");MyThreadt2=newMyThread("线程B");// 启动线程(注意:调用start()才会启动新线程,调用run()只是普通方法调用)t1.start();t2.start();}}

2.2 方式二:实现 Runnable 接口

实现步骤:

  1. 定义一个类实现Runnable接口
  2. 实现run()方法,编写线程执行的任务逻辑
  3. 创建该实现类的实例
  4. 将实例作为参数传入Thread的构造方法,创建 Thread 对象
  5. 调用 Thread 对象的start()方法启动线程
/** * 方式二:实现 Runnable 接口创建线程 */publicclassMyRunnableimplementsRunnable{// 实现run方法,编写线程任务@Overridepublicvoidrun(){for(inti=0;i<5;i++){System.out.println(Thread.currentThread().getName()+" 执行:"+i);try{Thread.sleep(200);}catch(InterruptedExceptione){e.printStackTrace();}}}// 测试publicstaticvoidmain(String[]args){// 创建任务对象MyRunnabletask=newMyRunnable();// 将任务对象传给Thread,创建多个线程执行同一个任务Threadt1=newThread(task,"线程A");Threadt2=newThread(task,"线程B");t1.start();t2.start();}}

注意:Runnable接口只有一个run()方法,它本身不具备启动线程的能力,最终还是要靠Thread类的start()方法来启动线程。Runnable的作用是封装线程要执行的任务。


三、核心区别多维度对比

3.1 对比总表

对比维度继承 Thread 类实现 Runnable 接口
本质继承一个线程类实现一个任务接口
单继承限制受 Java 单继承限制,子类不能再继承其他类不受单继承限制,还可以同时继承其他类、实现其他接口
资源共享多个线程间难以共享资源,需借助静态变量天然支持多个线程共享同一个任务对象中的资源
代码耦合度线程对象和任务逻辑绑定在一起,耦合度高任务逻辑与线程对象分离,解耦性好
代码复用性任务只能被该线程类使用,复用性差任务可以被多种线程、线程池复用,复用性强
线程池支持不支持直接放入线程池执行完美兼容线程池,是实际开发的标准用法
适用场景简单的单线程场景、无需共享资源的场景多线程共享资源、复杂业务、实际项目开发

3.2 详细解读

1. 单继承限制(最本质区别)

Java 是单继承语言,一个类只能有一个直接父类。如果选择继承Thread类,那么这个类就不能再继承其他任何类了,这会大大限制类的扩展性。

而实现Runnable接口完全没有这个问题,一个类可以同时实现多个接口,还可以继承其他父类,灵活性更高。

2. 资源共享能力

这是两者最直观的区别。实现 Runnable 接口可以很方便地让多个线程共享同一份资源,而继承 Thread 类做不到这一点。

我们用经典的“多窗口售票”案例来演示:

案例需求:3 个窗口同时卖 100 张票,总票数是共享的。

❌ 继承 Thread 实现(需要用静态变量共享)
publicclassTicketThreadextendsThread{// 必须用 static 静态变量,才能让多个线程对象共享privatestaticinttickets=100;publicTicketThread(Stringname){super(name);}@Overridepublicvoidrun(){while(tickets>0){System.out.println(getName()+" 卖出第 "+tickets--+" 张票");try{Thread.sleep(10);}catch(InterruptedExceptione){e.printStackTrace();}}}publicstaticvoidmain(String[]args){// 每个线程对象都有自己的成员变量,必须靠 static 共享newTicketThread("窗口1").start();newTicketThread("窗口2").start();newTicketThread("窗口3").start();}}
✅ 实现 Runnable(天然共享)
publicclassTicketRunnableimplementsRunnable{// 普通成员变量即可,多个线程共享同一个对象privateinttickets=100;@Overridepublicvoidrun(){while(tickets>0){System.out.println(Thread.currentThread().getName()+" 卖出第 "+tickets--+" 张票");try{Thread.sleep(10);}catch(InterruptedExceptione){e.printStackTrace();}}}publicstaticvoidmain(String[]args){// 只创建一个任务对象,交给3个线程执行TicketRunnabletask=newTicketRunnable();newThread(task,"窗口1").start();newThread(task,"窗口2").start();newThread(task,"窗口3").start();}}

对比结论:

  • 继承 Thread 的方式必须借助static静态变量才能共享资源,而静态变量生命周期长,容易带来其他问题
  • 实现 Runnable 的方式只需要创建一个任务对象,多个线程共享该对象的成员变量,更加自然合理
3. 代码解耦与复用
  • 继承Thread:线程对象和任务逻辑绑定死了,一个线程类只能做一件事,复用性差
  • 实现Runnable:把「线程要执行的任务」单独封装成一个对象,和线程本身解耦。同一个任务可以交给不同的线程执行,也可以交给线程池执行,复用性极强
4. 与线程池的兼容性

在实际企业开发中,我们几乎不会手动 new Thread,而是使用线程池来管理线程。而线程池只能接收Runnable或Callable类型的任务,不能直接接收 Thread 子类。

从这一点来说,实现 Runnable 接口是工业界的标准做法,而继承 Thread 更多只出现在入门教学中。


四、开发中如何选择?

推荐原则

  1. 优先选择实现 Runnable 接口

    这是绝大多数场景下的最佳选择,尤其是在需要多线程共享资源、需要良好扩展性、或者配合线程池使用的场景。

  2. 什么时候可以用继承 Thread?

    • 非常简单的单线程场景,只是为了快速测试
    • 该类本身就是一个线程实体,不需要再继承其他类
    • 教学演示、入门练习

行业共识

在真实的 Java 后端开发中,99% 的场景都会使用 Runnable(或 Callable)来定义线程任务,配合线程池来执行。直接继承 Thread 类创建线程的写法几乎不会出现在生产代码中,因为它的扩展性差、资源浪费严重,也不利于线程管理。


五、学习总结

通过这次作业,我搞懂了继承Thread和实现Runnable这两种创建线程方式的区别。以前只知道两种写法都能运行线程,不知道背后的设计思想和适用场景差异这么大。

我最大的收获有两点:

  1. 面向接口编程的优势:Runnable接口完美体现了面向接口编程的思想,它把「线程执行的任务」和「线程本身」分离开,带来了更好的扩展性、复用性和解耦性。
  2. 资源共享的设计差异:通过售票案例的对比,我直观地感受到了两种方式在资源共享上的区别,也理解了为什么实际开发都推荐用Runnable。

如果觉得这篇文章对你有帮助,欢迎点赞、收藏、关注!有任何问题可以在评论区留言交流~

相关新闻

  • 深度学习周报(6.22~6.28)
  • 性价比高的捆扎绳服务周到的公司
  • Agent后端-记忆RAG和上下文管理怎么做才像样

最新新闻

  • Django可观测性基建:集成 Sentry/Middleware 构建全链路追踪与异常监控体系
  • Mate Engine:开源免费的虚拟桌面伴侣,支持自定义VRM模型和丰富功能
  • I2C从机陈旧数据问题:MSPM0硬件机制与软件刷新流程详解
  • 3步解决老旧电视盒子卡顿问题:创维E900V22C变身专业4K播放器实战指南
  • 唐山路北区本地开锁行业基础流程与常见收费标准科普解读
  • 面试总说不出亮点?双非应届生秋招求职,请提前准备一个企业级AI应用案例

日新闻

  • ENVI5.3.1实战:基于Landsat 8影像的区域无缝镶嵌与精准裁剪
  • 3步完成HS2-HF Patch安装:新手快速打造完美HoneySelect2体验
  • 微信好友检测终极指南:3分钟发现谁已悄悄删除你

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号