news 2026/7/6 3:07:36

Java 多线程保姆级教程:线程创建、状态流转、锁机制、线程池,一篇讲透

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java 多线程保姆级教程:线程创建、状态流转、锁机制、线程池,一篇讲透

前言

多线程是大一 Java 课程的重点内容,也是期末考试、计算机二级的高频考点。很多同学刚学多线程时,分不清进程和线程,写售票程序时经常出现车票超卖,不知道怎么解决线程安全问题。本篇文章全部使用大一能看懂的基础语法,搭配完整可运行代码,把线程的全部基础知识点讲清楚。

一、进程和线程的区别

1. 基础概念

  1. 进程:电脑上运行的软件就是一个进程。比如你打开 QQ、浏览器,每一个软件都会单独占用一块内存,进程之间互不干扰。进程是操作系统分配电脑内存资源的最小单位。
  2. 线程:一个进程里面可以同时运行多条线程。比如音乐软件一边播放歌曲,一边下载歌词,播放音乐、下载歌词就是两条独立的线程。线程是 CPU 执行任务的最小单位。

2. 通俗例子

把进程比作一家工厂,工厂有厂房、原材料;线程就是工厂里的工人,多名工人共用工厂的厂房和物料,各自干自己的活。

3. 简单对比

对比项进程线程
资源有独立内存空间共用进程的内存
开销开启、关闭很消耗电脑性能创建开销很小
运行关系进程互相独立一条线程出错,整个程序会崩溃

二、Java 创建线程的 3 种方式

大一考试常考 3 种创建写法,全部可以直接运行。

方式 1:继承 Thread 类

自定义类继承Thread,重写run()方法,线程运行的代码全部写在 run 方法里,调用start()启动线程。

public class TestThread extends Thread { @Override public void run() { // 线程要执行的代码 for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); } } public static void main(String[] args) { TestThread t = new TestThread(); t.setName("子线程"); t.start(); // 开启新线程 } }

💡易错点:直接调用run()只是普通方法调用,不会开启新线程,只有start()才能创建线程。

方式 2:实现 Runnable 接口

Java 一个类只能继承一个父类,如果已经继承了别的类,就可以实现 Runnable 接口来创建线程。

public class TestRunnable implements Runnable { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); } } public static void main(String[] args) { TestRunnable task = new TestRunnable(); Thread t = new Thread(task, "子线程"); t.start(); } }

优点:同一个任务可以交给多个线程执行,代码耦合度更低。

方式 3:Callable 实现带返回值的线程

Runnable 线程运行结束后拿不到结果,Callable 可以在线程执行完成后返回计算结果,配合 FutureTask 获取返回值。

import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class TestCallable implements Callable<Integer> { @Override public Integer call() throws Exception { // 计算1到100的和 int sum = 0; for (int i = 1; i <= 100; i++) { sum += i; } return sum; } public static void main(String[] args) throws Exception { Callable<Integer> callable = new TestCallable(); FutureTask<Integer> futureTask = new FutureTask<>(callable); new Thread(futureTask).start(); // 获取线程运行结果 System.out.println("1~100求和:" + futureTask.get()); } }

三、线程的 6 种状态

大一期末必考线程生命周期,一共 6 种状态:

  1. 新建 NEW:new 出线程对象,还没有调用 start () 方法。
  2. 就绪 RUNNABLE:调用 start () 之后,线程排队等待 CPU 分配时间片。
  3. 运行 RUNNING:CPU 拿到时间片,线程开始执行 run 方法。
  4. 阻塞 BLOCKED:争抢锁失败,线程卡在门外等待锁释放。
  5. 等待 WAITING:调用无参 wait ()、join (),线程一直等待,必须由别的线程唤醒。
  6. 超时等待 TIMED_WAITING:调用sleep(1000),等待 1 秒之后自动恢复就绪状态。
  7. 终止 TERMINATED:run 方法运行结束,线程彻底结束。

四、常用线程方法

  1. sleep(毫秒):让当前线程休眠,休眠期间不会释放锁。
  2. join():等待子线程运行完毕,主线程再继续往下走。
  3. setDaemon(true):设置守护线程,主线程结束,守护线程自动关闭。
  4. currentThread():获取当前正在运行的线程对象。

五、线程安全问题(期末考试高频大题)

1. 为什么会出现线程安全问题

多个线程同时操作同一个共享变量,CPU 随时切换线程,就会出现数据错乱。 经典售票案例:多个窗口售卖车票,不加锁会出现一张车票被多次卖出。

2. 3 种解决办法

方案 1:synchronized 同步锁

Java 自带的关键字锁,有 3 种写法:

  1. 修饰普通方法,锁对象为 this
  2. 修饰静态方法,锁对象为类的 class 对象
  3. 同步代码块,自己指定锁对象
//同步代码块 Object lock = new Object(); synchronized (lock){ //售票业务代码 }
方案 2:Lock 显式锁

JUC 包下的 ReentrantLock,手动上锁、手动解锁。

import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Ticket { private Lock lock = new ReentrantLock(); public void sale(){ lock.lock(); try { //售票业务 }finally { lock.unlock(); } } }

注意:解锁必须写在 finally 里面,防止程序报错锁无法释放。

方案 3:volatile 关键字

volatile 可以保证多个线程看见同一个变量最新的值,但是不能解决 i++ 这类加减运算的安全问题,只适合简单变量读写。

六、线程池入门

频繁创建销毁线程会消耗电脑性能,线程池可以重复使用线程,大一只需要掌握基础概念即可。

1. 核心参数

  1. corePoolSize:核心线程数量,核心线程不会被回收
  2. maximumPoolSize:线程池最大线程数
  3. keepAliveTime:多余线程空闲之后的存活时间
  4. workQueue:等待队列,任务排队执行
  5. 拒绝策略:任务满了之后的处理方案

2. JDK 自带 4 种线程池

  1. newFixedThreadPool:固定线程数量
  2. newSingleThreadExecutor:只有一条线程
  3. newCachedThreadPool:线程数量自动扩容
  4. newScheduledThreadPool:定时执行任务
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/6 3:03:39

GPU打满却吞吐不涨?SGLang用Tracing+AI Agent揪出推理“黑盒”卡点

3月28日下午&#xff0c;龙蜥社区SGLang开发者苏峰和智算联盟委员常怀鑫在沐“蜥”芯生MeetUp上&#xff0c;扔出了一个多数大模型部署团队早晚会撞上的问题&#xff1a;GPU明明显示已打满&#xff0c;CPU也没闲着&#xff0c;可推理吞吐就是卡在一个数上&#xff0c;再怎么加请…

作者头像 李华
网站建设 2026/7/6 3:03:01

微软推送KB5095189:Windows 11 OOBE开箱即用体验迎来新一轮优化

六月底&#xff0c;微软悄然向Windows 11版本24H2和25H2推送了一项特殊的补丁——KB5095189。说它特殊&#xff0c;是因为这并非传统意义上修补系统漏洞的累积更新&#xff0c;而是一枚专门瞄准"开箱即用体验"&#xff08;Out-of-Box Experience&#xff0c;简称OOBE…

作者头像 李华
网站建设 2026/7/6 3:02:25

Docker 入门:概念、安装与配置

文章目录[toc]1 Docker 简介1.1 为什么需要 Docker1.2 容器与虚拟机比较1.3 Docker 的优势1.4 Docker 与 Podman 比较2 Docker 安装与配置2.1 Docker 的基本组成2.2 CentOS 7 安装 Docker2.3 配置阿里云镜像加速器2.4 验证安装2.5 Docker 为什么比虚拟机快1 Docker 简介 1.1 为…

作者头像 李华
网站建设 2026/7/6 2:58:16

obsidian中Local REST API with MCP插件mcp服务连接失败

配置 首先在Local REST API with MCP选项中的settings中打开enable non-encrypted&#xff08;HTTP&#xff09;sever。 然后打开配置文件&#xff08;.claude.json&#xff09;&#xff0c;找到"mcpServers"&#xff0c;在当中添加"obsidian"的配置&#…

作者头像 李华
网站建设 2026/7/6 2:57:45

Display Driver Uninstaller技术解析:显卡驱动深度清理方案

Display Driver Uninstaller技术解析&#xff1a;显卡驱动深度清理方案 【免费下载链接】display-drivers-uninstaller Display Driver Uninstaller (DDU) a driver removal utility / cleaner utility 项目地址: https://gitcode.com/gh_mirrors/di/display-drivers-uninsta…

作者头像 李华