Java 多线程基础
· 7 min read
多线程:充分利用计算机资源,同时执行不同的操作
一、操作系统简介
操作系统的作用
帮助上层应用程序屏蔽掉硬件的丑陋接口。
操作系统的发展史
- 手工操作
- 批处理系统
- 多道批处理
- 分时系统
- 实时系统
进程和线程
- 进程:正在执行的程序,其实就是一块内存区域,内部存储着程序的资源
- 线程:程序被 CPU 调度的最小单位
二、Java 多线程实现
Java 中创建线程的两种方式:
- 继承
Thread类,重写run()方法 - 实现
Runnable接口,实现run()方法
核心方法
| 方法 | 说明 |
|---|---|
run() | 线程执行时要执行的代码 |
start() | 启动一个线程 |
三、线程的生命周期
| 状态 | 进入方式 | 退出方式 |
|---|---|---|
NEW | new Thread() | start() |
RUNNABLE | start()、唤醒、超时、获得锁 | 时间片用完、yield()、等待资源 |
BLOCKED | 等待 synchronized 锁 | 获得锁 |
WAITING | wait()、join()、LockSupport.park() | notify()、notifyAll()、interrupt() |
TIMED_WAITING | sleep()、wait(timeout)、join(timeout) | 时间到、被唤醒、interrupt() |
TERMINATED | run() 执行完毕、异常退出 | - |
四、线程中的相关方法
| 方法 | 说明 |
|---|---|
sleep() | 睡眠,让线程暂停执行 |
setPriority() | 设置优先级 1~10,默认为 5 |
join() | 让主线程等待这个子线程执行完毕 |
yield() | 让出 CPU,让别人执行一下 |
interrupt() | 打断正在睡眠中的线程 |
五、线程同步
线程同步是指多个线程访问共享资源时,确保同一时刻只有一个线程能够访问,避免数据不一致的问题。
当多个线程共享同一个资源时,可以在某一个线程访问到这个资源时把这个资源暂时封锁,等待执行结束后释放这个锁,其他线程才可以进行执行。
等待其他线程释放锁,让线程更加安全。
实现方式
- 在方法声明上添加
synchronized关键字 - 在方法内部使用
synchronized代码块(更灵活,推荐) - 手动上锁
ReentrantLock(结束要释放锁)
六、死锁
死锁是指两个或多个线程互相持有对方需要的资源,导致所有线程都无法继续执行的状态。
七、生产者消费者模型
生产者消费者模型是多线程通信的经典设计模式,核心解决:生产者生产数据、消费者消费数据,两者速度不一致时,通过缓冲区解耦,保证线程安全、避免数据丢失 / 重复消费。
核心工具
-
BlockingQueue阻塞队列(JDK 封装好的线程安全队列,自动实现等待 / 唤醒,开发首选)- 当队列中没有数据时,需要拿数据的线程会被阻塞,直到队列中有数据才继续工作
-
AtomicInteger= 线程安全的 int 计数器- Java 提供的原子操作类,专门解决多线程下
i++不安全的问题
- Java 提供的原子操作类,专门解决多线程下
八、线程池
线程的创建和销毁是比较消耗性能的操作,线程池正是为解决此问题而生。
作用
- 复用线程,不频繁创建销毁,省资源
- 控制并发数,防止线程爆炸卡死
- 统一管理任务,提高响应速度
Java 线程池五大核心参数
- 核心线程数
corePoolSize - 最大线程数
maximumPoolSize - 空闲超时
keepAliveTime - 时间单位
unit - 阻塞队列
workQueue
四种拒绝策略
| 拒绝策略 | 说明 |
|---|---|
AbortPolicy | 直接抛异常(默认) |
CallerRunsPolicy | 交给调用者线程执行 |
DiscardPolicy | 丢弃当前任务 |
DiscardOldestPolicy | 丢弃队列中最老的任务 |
4 种常用内置线程池
newFixedThreadPool— 固定线程数newSingleThreadExecutor— 单线程串行newCachedThreadPool— 弹性缓存线程(空闲自动回收)newScheduledThreadPool— 定时 / 周期任务