5.Java线程创建全攻略:5种写法 + 高频面试题解析

目录

一、多线程基础概念

[1. 线程与进程的关系](#1. 线程与进程的关系)

[2. 线程状态:Thread.sleep(millis: 1000)](#2. 线程状态:Thread.sleep(millis: 1000))

[3. 方法重写要求](#3. 方法重写要求)

二、线程创建的几种写法

[写法1:继承 Thread,重写 run](#写法1:继承 Thread,重写 run)

[写法2:实现 Runnable,搭配 Thread执行](#写法2:实现 Runnable,搭配 Thread执行)

[写法3:继承 Thread,使用匿名内部类](#写法3:继承 Thread,使用匿名内部类)

[写法4:实现 Runnable,使用匿名内部类](#写法4:实现 Runnable,使用匿名内部类)

写法5:【简化】lambda表达式

[三、常见面试题:Thread对象与 start()的关系](#三、常见面试题:Thread对象与 start()的关系)

[问题:多次调用 start()会怎样?](#问题:多次调用 start()会怎样?)

[四、补充:高耦合 vs 低耦合(生活类比)](#四、补充:高耦合 vs 低耦合(生活类比))

五、包(package)的概念


一、多线程基础概念

1. 线程与进程的关系

  • 线程是轻量级进程 ,进程是重量级进程。

  • 进程是操作系统资源分配的基本单位 ,线程是操作系统调度执行的基本单位。

  • 进程之间不会相互影响 ,但线程可能会相互影响(因为线程共享进程资源)。

  • 进程内部包含线程,同一个进程的多个线程之间共享同一份资源。

  • 线程创建不需要申请资源,销毁也不需要释放资源(相比进程开销小)。

  • CPU发展瓶颈 → 多核心(多线程充分利用多核)。

2. 线程状态:Thread.sleep(millis: 1000)

  • sleep让当前线程进入阻塞状态(暂停执行指定时间)。

3. 方法重写要求

  • 父类方法和子类方法,签名完全一致(包括:方法名、参数列表、声明的抛出异常...)。

二、线程创建的几种写法

写法1:继承 Thread,重写 run

java 复制代码
class MyThread extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

写法2:实现 Runnable,搭配 Thread执行

java 复制代码
// 1. 定义 Runnable 实现类
class MyRunnable implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

// 2. 创建线程
public class Demo3 {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable r = new MyRunnable();
        Thread t = new Thread(r);
        t.start(); // 启动新线程,执行 Runnable 内部的 run
        
        while (true) {
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}
  • Runnable自身一般不会单独执行 ,需要搭配"载体"(Thread)执行。

  • 不再需要重写 run(已实现在 Runnable中)。

  • 本质 :启动的新线程会执行 Runnable内部的 run方法。

写法3:继承 Thread,使用匿名内部类

java 复制代码
public class Demo3 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        };
        t.start(); // 记住:调用 start 才是真正创建线程
        
        while (true) {
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}
  • 步骤:

    1. 创建 Thread的子类(匿名内部类,无名字)。

    2. 重写 run。

    3. 创建 Thread子类的实例,并用 t引用指向。

  • 特点:方便、一次性使用。

写法4:实现 Runnable,使用匿名内部类

java 复制代码
public class Demo3 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        t.start();
        
        while (true) {
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}
  • 此处针对 Runnable定义匿名内部类,返回结果是一个 Runnable的引用,把这个引用传入 Thread。

写法5:【简化】lambda表达式

java 复制代码
public class Demo5 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (true) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.start();
        
        while (true) {
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}
  • 数据结构角度来看:枚举、lambda、反射。

  • lambda本质上是一个"匿名函数",很多地方都能支持。

  • Java 语法非常死板,必须得有类;最初 Java 和其他语言都有 lambda,先搞了个匿名内部类过渡。

  • 函数式接口 (如 Runnable是函数式接口)。


三、常见面试题:Thread对象与 start()的关系

问题:多次调用 start()会怎样?

java 复制代码
public static void main(String[] args) {
    Thread thread = new Thread(() -> {
        System.out.println("hello");
    });
    thread.start();
    thread.start(); // 报错!
    thread.start();
}
  • 报错:java.lang.IllegalThreadStateException: Thread already started

  • 原因:Java 约定,一个 Thread对象,和一个操作系统中的线程是"一一对应"关系。

  • 因此,一个 Thread对象,只能 start一次。

  • 后续学习 Thread上的其他方法/属性,都是控制这个对应系统中的线程。

四、补充:高耦合 vs 低耦合(生活类比)

  • 高耦合:女朋友生病了,我推掉所有工作,全身心在医院照顾 → 假设陌生人生病了,对我没啥影响,朋友圈点赞之交,该干啥干啥,影响非常小。

  • 低耦合 :任务(Runnable)和线程(Thread)解耦 → 任务和线程概念绑定(继承 Thread)时,若改成其他形式,需要大规模修改代码;而 Runnable没有和线程概念绑定,任务可方便地迁移到其他载体上。


五、包(package)的概念

  • Java 中类太多(标准库、第三方库、自己写的)→ 乱。

  • 包:一组有关系的类放到一起。

  • 包默认情况下不会引入到代码中,使当前代码引入的类比较少、不容易乱。

  • import java.util.*;:导入包中所有类(不推荐)。

  • 最基础常用的:import java.lang.*(默认导入)。

相关推荐
紧跟先前的步伐16 分钟前
Go AI Agent 实战 03|Token、上下文窗口与模型调用成本
java·人工智能·golang
benchmark_cc29 分钟前
Python 量化系统如何设计统一的数据访问接口:从策略解耦到数据层架构
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
const_qiu42 分钟前
第四章 00:开篇 —— 从「会聊天」到「记得住、会干活、能协作」
java·开发语言·人工智能·python
Wang's Blog1 小时前
Java 项目实战: 交友项目 - 个人资料管理的更新接口实现与坑
java·开发语言·交友
Promising_GEO1 小时前
GEE实战02期:从卫星波段开始:利用 Sentinel-2 自己计算 NDVI
java·sentinel·遥感·空间分析
大文说跨境1 小时前
亚马逊多账号管理浏览器怎么选?云登/紫鸟/AdsPower 对比
java·前端·自动化
CoderYanger1 小时前
Java EE 进阶:4.Spring Web MVC 入门(第一弹)
java·开发语言·前端·spring·面试·java-ee·mvc
估值探索者1 小时前
【Python量化选股流水线 #04】选股器好不好用?「昨日候选→今日表现」回看验收
开发语言·python·股票数据·股票数据api接口
顽疲2 小时前
java springboot vue 养老系统源码详解:请假 care_leave 销假与床位停费日扣实践
java·vue.js·spring boot
XIAEE2 小时前
一个即时通讯项目是怎么长出来的:(Spring Boot 3 + Vue 3 微前端 + 悟空 IM + LiveKit)
java·spring