news 2026/5/16 12:40:02

谁在调用?线程类的构造与静态块解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
谁在调用?线程类的构造与静态块解析

文章目录

  • 谁在调用?线程类的构造与静态块解析 ?
    • 线程的创建方式
      • 1. 继承Thread类的方式
      • 2. 实现Runnable接口的方式
    • 静态代码块和构造方法的区别
      • 静态代码块
      • 构造方法
    • 线程创建与静态代码块的结合
      • 案例1:静态代码块在多线程环境下的执行情况
      • 案例2:静态代码块中的多线程问题
    • 结论
    • 因此,在编写多线程程序时,我们需要特别注意静态代码块和构造方法的区别,避免在不合适的地方启动线程或者执行其他敏感的操作。
      • 📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!

谁在调用?线程类的构造与静态块解析 ?

大家好,闫工又和大家见面了!今天咱们要聊的主题有点意思,是关于Java中的线程创建方式以及静态代码块的执行时机。这个问题看似简单,但其中涉及的知识点可不少,而且很容易让人掉进一些“坑”里。所以,今天的分享,我会结合实际案例,详细解析这两个知识点,并且带大家一起来看看“谁在调用”。

线程的创建方式

说到线程的创建,Java中主要有两种方式:继承Thread类和实现Runnable接口。除此之外,还有第三种方式,那就是通过Callable接口来实现更复杂的任务处理。不过,今天我们主要围绕前两种方式进行讨论。

1. 继承Thread类的方式

这种方式应该是大家最熟悉的了。继承Thread类之后,我们需要重写run()方法,并在适当的时候调用start()方法来启动线程。代码大致如下:

classMyThreadextendsThread{@Overridepublicvoidrun(){System.out.println("闫工说:我在执行任务!");}}publicclassMainClass{publicstaticvoidmain(String[]args){MyThreadthread=newMyThread();thread.start();// 启动线程,调用run方法}}

这里有个细节需要注意,那就是start()方法和run()方法的区别。start()方法会启动一个新的线程,并在该线程中执行run()方法;而直接调用run()方法,则是使用当前的主线程来执行任务,这样并没有实现多线程的效果。

2. 实现Runnable接口的方式

相比于继承Thread类,实现Runnable接口的方式更加灵活。因为Java只支持单继承,所以如果我们已经继承了其他类,就无法再通过继承Thread类的方式来创建线程了。这时候,实现Runnable接口就是更好的选择。

classMyRunnableimplementsRunnable{@Overridepublicvoidrun(){System.out.println("闫工说:我在执行任务!");}}publicclassMainClass{publicstaticvoidmain(String[]args){MyRunnablerunnable=newMyRunnable();Threadthread=newThread(runnable);thread.start();// 启动线程,调用run方法}}

这种方式的好处在于,我们可以将任务逻辑封装在Runnable接口的实现类中,而线程的管理则由Thread类来完成。不过,有一点需要注意的是,在Thread类的构造函数中,我们传入了一个实现了Runnable接口的对象,这样Thread类才会知道如何执行我们的任务。

静态代码块和构造方法的区别

好了,现在回到今天的主题,“谁在调用?”其实这个问题主要涉及到静态代码块和构造方法的区别。在Java中,静态代码块是在类加载时就会被执行的,而构造方法则是每次创建对象时才会被调用的。

静态代码块

静态代码块是写在类中的一个特殊结构,它会被JVM在类第一次被加载的时候执行。需要注意的是,静态代码块只会在类被加载时执行一次,无论这个类被实例化多少次。

classStaticBlock{static{System.out.println("闫工说:静态代码块被执行了!");}}publicclassMainClass{publicstaticvoidmain(String[]args){// 只要MainClass被加载,StaticBlock也会被加载newStaticBlock();}}

构造方法

构造方法是在创建对象时调用的,每次创建对象都会执行一次。

classConstructorExample{publicConstructorExample(){System.out.println("闫工说:构造方法被执行了!");}}publicclassMainClass{publicstaticvoidmain(String[]args){newConstructorExample();// 第一次调用构造方法newConstructorExample();// 第二次调用构造方法}}

线程创建与静态代码块的结合

现在,我们来看看线程创建和静态代码块之间有什么关联。其实,在某些情况下,如果我们不注意静态代码块的使用,可能会导致一些意想不到的结果。

案例1:静态代码块在多线程环境下的执行情况

假设我们有一个类MyThread,它继承了Thread类,并且在这个类中定义了一个静态代码块和一个构造方法:

classMyThreadextendsThread{static{System.out.println("闫工说:静态代码块被执行了!");}publicMyThread(){System.out.println("闫工说:构造方法被执行了!");}@Overridepublicvoidrun(){System.out.println("闫工说:线程在执行任务!");}}publicclassMainClass{publicstaticvoidmain(String[]args){newMyThread().start();newMyThread().start();}}

运行这段代码,控制台会输出什么呢?我们来分析一下:

  1. MainClass被执行时,首先会加载MyThread类。在类加载的时候,静态代码块会被执行一次,输出“闫工说:静态代码块被执行了!”。
  2. 然后,在主线程中创建第一个MyThread对象,这时候构造方法被调用,输出“闫工说:构造方法被执行了!”。
  3. 调用start()方法,启动线程,执行run()方法,输出“闫工说:线程在执行任务!”。
  4. 接着,创建第二个MyThread对象,同样会调用构造方法,输出“闫工说:构造方法被执行了!”。
  5. 再次调用start()方法,启动另一个线程,执行run()方法。

所以,最终的输出结果应该是:

闫工说:静态代码块被执行了! 闫工说:构造方法被执行了! 闫工说:线程在执行任务! 闫工说:构造方法被执行了! 闫工说:线程在执行任务!

通过这个案例,我们可以看到静态代码块只会在类加载时被调用一次,而构造方法则会随着对象的创建而多次被调用。

案例2:静态代码块中的多线程问题

有时候,我们可能会不小心在静态代码块中启动线程,这样可能会导致一些意想不到的问题。例如:

classMyThreadextendsThread{static{newMyThread().start();// 在静态代码块中启动线程System.out.println("闫工说:静态代码块被执行了!");}publicMyThread(){System.out.println("闫工说:构造方法被执行了!");}@Overridepublicvoidrun(){System.out.println("闫工说:线程在执行任务!");}}publicclassMainClass{publicstaticvoidmain(String[]args){newMyThread().start();}}

这段代码可能会引发一些问题。因为当MyThread类被加载时,静态代码块会被执行,从而创建并启动一个线程。然而,在这个过程中,我们可能还没有准备好处理这个额外的线程。

运行这段代码,控制台会输出:

  1. 静态代码块被执行,构造方法被执行一次,然后启动线程。
  2. 主线程继续执行,创建另一个MyThread对象,并启动它。

所以,最终的输出可能是这样的:

闫工说:构造方法被执行了! 闫工说:线程在执行任务! 闫工说:静态代码块被执行了! 闫工说:构造方法被执行了! 闫工说:线程在执行任务!

但是,这里有一个问题。在静态代码块中创建并启动了一个MyThread对象,这可能会导致一些竞态条件或者资源竞争的问题,尤其是在多线程环境下。

结论

通过以上的分析和案例,我们可以得出以下结论:

  1. 静态代码块是在类加载时被执行的,只执行一次。
  2. 构造方法是每次创建对象时被调用的,可能会被多次调用。
  3. 在静态代码块中启动线程需要特别小心,以免引发不可预测的问题。

因此,在编写多线程程序时,我们需要特别注意静态代码块和构造方法的区别,避免在不合适的地方启动线程或者执行其他敏感的操作。

📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!

成体系的面试题,无论你是大佬还是小白,都需要一套JAVA体系的面试题,我已经上岸了!你也想上岸吗?

闫工精心准备了程序准备面试?想系统提升技术实力?闫工精心整理了1000+ 套涵盖前端、后端、算法、数据库、操作系统、网络、设计模式等方向的面试真题 + 详细解析,并附赠高频考点总结、简历模板、面经合集等实用资料!

✅ 覆盖大厂高频题型
✅ 按知识点分类,查漏补缺超方便
✅ 持续更新,助你拿下心仪 Offer!

📥免费领取👉 点击这里获取资料

已帮助数千位开发者成功上岸,下一个就是你!✨

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

终极免费文档下载利器:kill-doc一键解决所有下载难题

终极免费文档下载利器:kill-doc一键解决所有下载难题 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该脚本就是为了解…

作者头像 李华
网站建设 2026/5/10 20:47:58

MediaPipe Hands部署指南:21

MediaPipe Hands部署指南:21个3D关键点高精度手势识别与彩虹骨骼可视化 1. 引言 1.1 AI 手势识别与追踪 在人机交互、虚拟现实、智能监控和无障碍技术快速发展的今天,手势识别正成为连接人类动作与数字世界的桥梁。相比传统的触控或语音输入&#xff…

作者头像 李华
网站建设 2026/5/12 16:46:54

3步解锁原神抽卡数据隐藏价值:从混沌到洞察的数据侦探之旅

3步解锁原神抽卡数据隐藏价值:从混沌到洞察的数据侦探之旅 【免费下载链接】genshin-wish-export biuuu/genshin-wish-export - 一个使用Electron制作的原神祈愿记录导出工具,它可以通过读取游戏日志或代理模式获取访问游戏祈愿记录API所需的authKey。 …

作者头像 李华
网站建设 2026/5/14 21:27:01

在IDEA中设置核心配置文件的模板

模板内容&#xff1b; <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><prope…

作者头像 李华
网站建设 2026/5/16 2:18:20

2D/3D骨骼检测全对比:5个主流模型,云端3小时深度评测

2D/3D骨骼检测全对比&#xff1a;5个主流模型&#xff0c;云端3小时深度评测 1. 为什么需要骨骼检测技术&#xff1f; 想象一下你在玩VR游戏时&#xff0c;电脑能实时捕捉你的每个动作——这就是骨骼检测技术的魔力。作为VR项目的技术选型负责人&#xff0c;面对各种论文里的…

作者头像 李华
网站建设 2026/5/13 1:26:48

Beyond Compare 5永久授权全攻略:4种秘籍实现完全激活

Beyond Compare 5永久授权全攻略&#xff1a;4种秘籍实现完全激活 【免费下载链接】BCompare_Keygen Keygen for BCompare 5 项目地址: https://gitcode.com/gh_mirrors/bc/BCompare_Keygen 还在为Beyond Compare 5的30天试用期到期而焦虑吗&#xff1f;这款专业的文件对…

作者头像 李华