第15篇:Java多线程零基础入门,进程线程、线程创建方式、线程生命周期、线程安全彻底吃透

前面14篇,我们搞定了:基础语法、面向对象、集合、IO流

从今天开始,正式进入Java进阶核心难点------多线程

多线程是Java进阶的分水岭,也是面试必考、项目必用的核心技术。

没有多线程,就没有高并发、没有秒杀系统、没有后台高性能服务。

很多新手学不懂多线程,是因为教程太抽象。本篇我用大白话+生活类比+极简代码,从零带你吃透多线程基础,零基础也能一次性看懂。

本篇核心学习目标:

  • 彻底分清进程和线程的区别

  • 掌握线程三大创建方式(面试必考)

  • 看懂线程优先级、守护线程

  • 吃透线程完整生命周期(5大状态)

  • 理解多线程安全问题产生的根本原因

  • 掌握最简单的线程安全解决方案

  • 搞定多线程入门所有面试题


一、进程与线程(通俗白话理解)

1.1 什么是进程?

进程:正在运行的软件程序,是系统资源分配的最小单位。

生活举例:打开微信、打开浏览器、打开IDEA,每一个运行的软件都是一个进程。

进程特点:独立内存、相互隔离、互不干扰

1.2 什么是线程?

线程:进程中的执行单元,是CPU调度的最小单位。

生活举例:

打开微信(进程),里面可以同时:聊天、刷朋友圈、接收消息、文件传输,每一个功能都是一个线程。

1.3 进程与线程核心区别(必背面试题)

对比维度 进程 线程
定义 程序运行实例,资源分配最小单位 进程执行单元,CPU调度最小单位
内存 独立内存,进程间隔离 共享进程内存,资源共享
开销 开销大、创建销毁慢 开销小、效率高
关系 一个进程至少包含1个线程 线程依赖进程存在
稳定性 一个进程崩溃不影响其他进程 一个线程崩溃,整个进程可能崩溃

核心总结:进程是大房子,线程是房间里的打工人;房子独立,工人共享资源。


二、线程三大创建方式(工作+面试必掌握)

2.1 方式一:继承Thread类(最简单)

步骤:

  1. 自定义类继承 Thread

  2. 重写 run() 方法(线程执行任务)

  3. 创建子类对象,调用 start() 启动线程

java 复制代码
// 1. 自定义线程类
public class MyThread extends Thread{
    @Override
    public void run() {
        // 线程执行的任务
        for (int i = 0; i < 10; i++) {
            System.out.println("线程执行:" + i);
        }
    }
}

// 测试类
public class ThreadDemo {
    public static void main(String[] args) {
        MyThread t = new MyThread();
        t.start(); // 启动线程
    }
}

注意:必须调用start(),不是run()!直接调用run()只是普通方法,不是多线程!

2.2 方式二:实现Runnable接口(推荐、解耦)

Java单继承多实现,这种方式避免单继承限制,任务和线程分离,更灵活。

java 复制代码
// 1. 实现任务接口
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("Runnable线程:" + i);
        }
    }
}

// 测试
public class ThreadDemo {
    public static void main(String[] args) {
        // 任务对象
        MyRunnable run = new MyRunnable();
        // 线程对象 + 任务对象
        Thread t = new Thread(run);
        t.start();
    }
}

2.3 方式三:Callable接口(有返回值、可抛异常)

前两种无返回值、不能捕获任务异常,Callable可以获取线程执行结果,多用于并发任务获取结果场景。

java 复制代码
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

// 带返回值的线程任务
public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }
        return sum;
    }
}

// 测试
public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        MyCallable call = new MyCallable();
        FutureTask<Integer> task = new FutureTask<>(call);
        Thread t = new Thread(task);
        t.start();
        // 获取线程返回结果
        System.out.println("结果:" + task.get());
    }
}

2.4 三种创建方式对比(面试必背)

创建方式 优点 缺点 场景
继承Thread 写法简单 单继承限制,无法继承其他类 简单临时线程
实现Runnable 解耦、灵活、共享任务 无返回值 日常开发首选
实现Callable 有返回值、可抛异常 写法复杂 需要获取线程结果

三、线程常用基础方法

java 复制代码
start()       // 启动线程
run()         // 线程任务逻辑
sleep()       // 线程休眠(毫秒),不释放锁
join()        // 线程插队,等待该线程执行完毕
yield()       // 线程礼让,让出CPU
setPriority() // 设置线程优先级
setDaemon()   // 设置守护线程
currentThread()// 获取当前线程对象

3.1 线程休眠sleep

让线程暂停指定时间,时间到自动恢复执行。

java 复制代码
Thread.sleep(1000); // 休眠1秒

3.2 守护线程(后台线程)

用户线程:前台任务,执行完程序才退出

守护线程:后台任务,所有用户线程结束,守护线程自动结束

典型场景:垃圾回收线程、日志监听、心跳检测。

java 复制代码
t.setDaemon(true); // 设置为守护线程

四、线程生命周期(五大状态,面试必考)

线程从创建到销毁,一共5种状态,全程闭环流转。

4.1 五大状态详解

  1. 新建状态 NEW:new线程对象,未启动

  2. 就绪状态 RUNNABLE:调用start(),等待CPU调度

  3. 运行状态 RUNNING:抢到CPU时间片,执行run方法

  4. 阻塞状态 BLOCKED/WAITING:休眠、等待锁、礼让,暂停执行

  5. 死亡状态 TERMINATED:任务执行完毕或异常终止

核心流转:新建 → 就绪 → 运行 → (阻塞) → 死亡


五、多线程安全问题(核心痛点)

5.1 为什么会出现线程不安全?

三个必备条件(同时满足就不安全):

  1. 多线程并发执行

  2. 共享同一个资源(变量、数据)

  3. 对资源进行读写修改操作

5.2 线程不安全代码演示

模拟售票场景,多线程卖同100张票,出现超卖、重复卖票问题。

java 复制代码
public class Ticket implements Runnable{
    // 共享票数
    private int ticket = 100;

    @Override
    public void run() {
        while (ticket > 0){
            System.out.println(Thread.currentThread().getName()+"卖出第"+ticket+"张票");
            ticket--;
        }
    }
}

// 测试:三个线程同时卖票
public class Test {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(ticket,"窗口1").start();
        new Thread(ticket,"窗口2").start();
        new Thread(ticket,"窗口3").start();
    }
}

运行结果:出现重复票、负数票,典型线程不安全!

5.3 最简解决方案:synchronized同步代码块

加锁!保证同一时间只有一个线程操作共享数据

java 复制代码
@Override
public void run() {
    while (true){
        // 同步锁:锁对象唯一
        synchronized (this) {
            if(ticket > 0){
                System.out.println(Thread.currentThread().getName()+"卖出第"+ticket+"张票");
                ticket--;
            }else{
                break;
            }
        }
    }
}

加锁之后:线程串行执行,数据安全,不会超卖重复!


六、新手高频易错坑

  1. start()才是启动线程,run()只是普通方法调用

  2. 线程启动后不一定立刻运行,需要抢夺CPU时间片

  3. 多线程操作共享变量必不安全,必须加锁

  4. sleep休眠不释放锁,wait会释放锁

  5. 守护线程随用户线程消亡,适合后台任务

  6. 线程只能启动一次,重复start()直接报错


七、本篇总结

本篇搞定多线程全部入门核心,记住核心口诀:

  • 进程是资源单位,线程是执行单位

  • 线程三种创建:Thread、Runnable、Callable

  • Runnable开发首选,Callable适合需要返回值场景

  • 线程五大生命周期:新建、就绪、运行、阻塞、死亡

  • 多线程并发读写共享资源 = 线程不安全

  • 同步锁synchronized解决线程安全问题

相关推荐
Raink老师1 小时前
【AI面试临阵磨枪-086】什么是 AI Agent Skill?与传统 Function Calling、Tool 的区别?
人工智能·面试·职场和发展
蝈理塘(/_\)大怨种1 小时前
类和对象 (上)
java·开发语言
小新1102 小时前
qt creator 将qInfo的输出日志写入日志文档,方便查看
开发语言·qt
我材不敲代码2 小时前
Python 函数核心:位置参数与关键字参数详解
java·前端·python
hssfscv2 小时前
QT的学习记录1
开发语言·qt·学习
SunnyDays10113 小时前
Python操作Excel批注:从基础添加到高级自定义的完整指南
开发语言·python·excel
Yyyyyy~3 小时前
【C++】数组篇
开发语言·c++
qq_333120973 小时前
C++高并发内存池的整体设计和实现思路_C 语言
java·c语言·c++
牛肉在哪里3 小时前
ros2 从零开始27 编写广播C++
开发语言·c++·机器人