一、前置基础:进程与线程核心概念

1. 进程

程序的一次运行过程,系统资源分配的最小单位;每个进程有独立内存空间,进程间资源不共享。

2. 线程

进程内部的独立执行路径,CPU 调度的最小单位;一个进程至少有 1 个主线程(main 线程);同一进程下多个线程共享堆内存、方法区,只独占栈内存。

3. 并发 & 并行

  • 并发:同一时间段,多个线程交替抢占 CPU 执行(单核 CPU 本质是并发)。
  • 并行:同一时刻,多个线程同时在多核 CPU 分别执行。

二、线程创建方式一:继承 Thread 类

1. 实现步骤(标准四步)

  1. 自定义类 继承 Thread 父类
  2. 重写 run () 方法:封装线程要执行的任务逻辑
  3. 创建自定义线程类实例对象
  4. 调用 start () 方法 启动线程,而非直接调用 run ()

2. 继承结构图示

java.lang.Thread 抽象父类
        ↑
自定义线程类 (extends Thread)
重写 run() 作为线程执行入口

3. 完整标准代码

// 1. 自定义线程类,继承Thread
public class MyThread extends Thread {
    private int flag;

    // 构造方法传参,区分不同线程任务
    public MyThread(int flag) {
        this.flag = flag;
    }

    // 2. 重写run方法:线程真正执行的任务体
    @Override
    public void run() {
        if (flag == 1) {
            for (int i = 0; i < 10; i++) {
                System.out.println("线程1执行:" + i);
            }
            System.out.println("线程1任务结束");
        } else {
            for (int i = 0; i < 10; i++) {
                System.out.println("线程2执行:" + i);
            }
            System.out.println("线程2任务结束");
        }
    }
}

三、线程启动规则与测试代码

1. 测试启动类

public class ThreadTest {
    public static void main(String[] args) {
        // 3. 创建线程对象
        MyThread t1 = new MyThread(1);
        MyThread t2 = new MyThread(2);

        // 4. 调用start() 开启新线程
        t1.start();
        t2.start();

        // 主线程独立执行,和子线程并发
        System.out.println("主线程main执行完毕");
    }
}

2. 核心硬性规则

  1. run () 只是普通成员方法直接调用 t1.run() 不会开启新线程,只是普通串行执行,依旧在 main 线程中运行。

  2. start () 是开启线程唯一方式

  • start () 是 native 本地方法,底层向 JVM 申请开辟新栈内存
  • 由 JVM 自动回调 run () 方法,真正实现多线程并发
  1. 一个线程对象只能调用一次 start ()重复调用会直接抛出:IllegalThreadStateException 非法线程状态异常。

  2. Java 单继承局限一旦继承 Thread 类,无法再继承其他任意父类,程序扩展性被限制。


四、多线程执行核心特性

  1. 抢占式调度机制CPU 时间片随机分配,哪个线程抢到资源就先执行,人为无法控制执行顺序

  2. 并发执行、互不阻塞main 主线程、子线程 1、子线程 2同时交替运行,彼此不会互相等待。

  3. 执行结果无序每次运行控制台打印顺序都不一样,由操作系统 CPU 调度策略决定。

  4. 主线程退出不影响子线程main 主线程执行结束退出,子线程会继续走完自己的任务,不会随主线程消亡

  5. 线程默认命名规则未手动设置名称时,默认:Thread-0Thread-1Thread-2……可用 getName() 获取线程名,setName("线程名") 自定义命名。


五、重点辨析:run () 与 start () 深度对比

表格

对比维度 run () 方法 start () 方法
方法类型 普通成员方法 native 本地方法
作用 封装线程任务逻辑 向 JVM 申请创建新线程
是否开新线程 不开启,普通串行执行 开启独立新线程
执行方式 手动直接调用 JVM 自动回调 run ()
调用次数 可无限重复调用 只能调用一次,多次抛异常

六、继承 Thread 类 优缺点完整总结

优点

  1. 写法简单直观,入门容易。
  2. 自定义类直接继承 Thread,可直接调用 Thread 类所有通用方法(sleep、getName、setName 等)。

缺点

  1. 受 Java单继承机制限制,不能再继承其他业务类。
  2. 线程和任务耦合在一起,线程对象和业务逻辑绑定,不方便复用。
  3. 多个线程任务代码冗余,无法共享同一个任务资源。
  4. 实际开发中极少使用,一般优先用 Runnable、Callable、线程池

七、补充必考易错点

  1. 不要把 循环、耗时操作 写在 main 主线程,应放到子线程 run () 中。
  2. 多线程无序不是代码问题,是CPU 抢占式调度的正常特性
  3. 只有调用 start () 才会开辟独立栈内存,run () 只是普通方法调用,无新栈。
  4. 线程生命周期:新建状态 → 就绪状态 → 运行状态 → 阻塞 / 终止状态。

 

更多推荐