Java多线程基础

8186

一、什么是多线程?

多线程(Multithreading) 是指在一个程序中同时执行多个任务的能力。它是现代软件开发中实现并发处理的核心技术。

🌟 类比理解: 想象一个家庭,每个成员都在做不同的事情:

妈妈在做饭爸爸在洗衣服孩子在写作业这些活动可以同时进行,互不干扰 —— 这就是多任务并行的现实映射。

✅ 实际应用场景:场景

说明

浏览器

多个标签页独立加载网页内容

手机应用

音乐播放、导航、聊天同时运行

服务器

同时响应成千上万用户的请求

游戏

渲染画面、处理输入、播放音效并行执行

二、并发 vs 并行这两个概念经常被混淆,但它们有本质区别:

概念

定义

特点

示例

并发(Concurrency)

多个任务在同一时间段内交替执行

单核CPU通过时间片轮转实现“看似同时”

单核电脑运行多个程序

并行(Parallelism)

多个任务在同一时刻真正同时执行

需要多核或多处理器支持

多核CPU上多个线程分别运行

🔍 关键区别:

并发是逻辑上的同时并行是物理上的同时代码语言:java复制// 并发示例:单线程模拟多个任务

while (true) {

执行任务A一小会;

执行任务B一小会;

}代码语言:java复制// 并行示例:多线程真正同时运行

new Thread(任务A).start();

new Thread(任务B).start();三、进程 vs 线程对比项

进程(Process)

线程(Thread)

定义

操作系统资源分配的基本单位

CPU调度的基本单位

内存空间

独立的地址空间

共享所属进程的内存

创建开销

大(需要分配资源)

小(共享资源)

通信方式

IPC(管道、消息队列等)

直接共享变量

切换成本

稳定性

一个崩溃不影响其他进程

一个线程崩溃可能导致整个进程终止

🎯 一句话总结:

进程 = 工厂线程 = 工厂里的工人多个工人(线程)共享同一个工厂(进程)的资源和空间四、创建线程的四种方式4.1 方式一:继承 Thread 类代码语言:java复制public class MyThread extends Thread {

@Override

public void run() {

System.out.println("我是线程:" + Thread.currentThread().getName());

}

public static void main(String[] args) {

MyThread thread = new MyThread();

thread.setName("线程1");

thread.start(); // 启动线程

}

}✅ 优点: 代码简洁直观

❌ 缺点: Java不支持多继承,无法再继承其他类

4.2 方式二:实现 Runnable 接口代码语言:java复制public class MyRunnable implements Runnable {

@Override

public void run() {

System.out.println("我是线程:" + Thread.currentThread().getName());

}

public static void main(String[] args) {

MyRunnable runnable = new MyRunnable();

Thread thread = new Thread(runnable, "线程2");

thread.start();

}

}✅ 优点:

避免单继承限制更符合“组合优于继承”的设计原则多个线程可共享同一个Runnable实例💡 推荐指数:★★★★☆

4.3 方式三:实现 Callable 接口 + FutureTask代码语言:java复制import java.util.concurrent.Callable;

import java.util.concurrent.FutureTask;

public class MyCallable implements Callable {

@Override

public String call() throws Exception {

return "我是线程:" + Thread.currentThread().getName();

}

public static void main(String[] args) throws Exception {

MyCallable callable = new MyCallable();

FutureTask futureTask = new FutureTask<>(callable);

Thread thread = new Thread(futureTask, "线程3");

thread.start();

// 获取线程执行结果(阻塞等待)

System.out.println(futureTask.get());

}

}✅ 优点:

可以返回执行结果支持泛型可抛出异常⚠️ 注意: get() 方法会阻塞主线程直到结果返回

4.4 方式四:使用线程池(推荐)代码语言:java复制import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class ThreadPool {

public static void main(String[] args) {

// 创建固定大小为2的线程池

ExecutorService executor = Executors.newFixedThreadPool(2);

// 提交任务

executor.execute(() ->

System.out.println("我是线程:" + Thread.currentThread().getName())

);

// 关闭线程池

executor.shutdown();

}

}✅ 优点:

避免频繁创建/销毁线程控制并发数量提高性能和资源利用率支持更多高级功能(定时任务、异步结果等)🚀 生产环境强烈推荐使用线程池!

四种方式对比总结方式

优点

缺点

使用场景

继承Thread

简单直接

不能继承其他类

简单演示

实现Runnable

灵活,可复用

无返回值

通用任务

实现Callable

有返回值,可抛异常

使用稍复杂

需要结果

线程池

高效,易管理

初始配置复杂

生产环境

五、线程核心控制机制5.1 线程休眠:Thread.sleep()让当前线程暂停指定时间,释放CPU给其他线程。

代码语言:java复制public class SleepThread extends Thread {

@Override

public void run() {

for (int i = 0; i < 5; i++) {

System.out.println("我是线程:" +

Thread.currentThread().getName() + ",i = " + i);

try {

Thread.sleep(1000); // 暂停1秒

} catch (InterruptedException e) {

System.out.println("线程被中断");

break;

}

}

}

}⚠️ 注意事项:

sleep() 不释放锁必须捕获 InterruptedException时间是近似值,受系统调度影响5.2 线程优先级设置线程获取CPU时间片的概率。

代码语言:java复制public class PriorityTest {

public static void main(String[] args) {

Thread thread1 = new Thread(() -> {

for (int i = 0; i < 5; i++) {

System.out.println("低优先级线程:" + i);

}

});

thread1.setPriority(Thread.MIN_PRIORITY); // 1

Thread thread2 = new Thread(() -> {

for (int i = 0; i < 5; i++) {

System.out.println("高优先级线程:" + i);

}

});

thread2.setPriority(Thread.MAX_PRIORITY); // 10

thread1.start();

thread2.start();

}

}⚠️ 重要提醒:

优先级不是绝对的,只是建议不同JVM实现可能有不同的调度策略不应依赖优先级来保证程序正确性5.3 守护线程(Daemon Thread)为其他线程提供服务的后台线程,当所有用户线程结束时,JVM会自动退出。

代码语言:java复制public class DaemonTest {

public static void main(String[] args) {

Thread daemonThread = new Thread(() -> {

while (true) {

System.out.println("我是守护线程,正在运行...");

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

break;

}

}

});

daemonThread.setDaemon(true); // 必须在start前设置

daemonThread.start();

System.out.println("主线程开始...");

try {

Thread.sleep(5000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("主线程结束");

// JVM退出,守护线程自动终止

}

}✅ 典型用途:

垃圾回收器日志记录心跳检测监控服务六、最佳实践与注意事项✅ 推荐做法:优先使用线程池 而非手动创建线程使用 try-with-resources 或 finally 确保资源释放避免过度使用高优先级线程守护线程不应持有关键资源注意线程安全问题(后续章节会深入讲解)❌ 避免陷阱:不要在循环中频繁创建线程不要忽略 InterruptedException不要假设线程执行顺序不要滥用高优先级总结Java多线程是构建高性能、响应式应用程序的基石。掌握以下核心要点:

代码语言:javascript代码运行次数:0运行复制并发 vs 并行 → 理解执行模型

进程 vs 线程 → 明确资源边界

四种创建方式 → 掌握不同场景选择

休眠/优先级/守护线程 → 控制线程行为

线程池 → 生产环境首选方案🎯 学习路径建议:

先掌握基本概念和创建方式理解线程生命周期学习线程同步与锁机制掌握线程池高级用法了解并发工具类(如CountDownLatch, CyclicBarrier等)多线程编程虽有挑战,但一旦掌握,你将能开发出真正高效的现代应用程序!