一、基础概念

(一) 线程(Thread)

  • 定义:程序内部的最小执行流程,是操作系统调度的基本单位。

  • 单线程程序:仅1条执行流程(如默认main方法流程),代码依次执行。

示例:

public static void main(String[] args) {
    // 单线程执行:依次执行循环逻辑
    for(int i=8; i<10; i++){
        System.out.println(i);
    }
}

(二) 多线程

  • 定义:从软硬件层面实现多条执行流程的技术,多条线程由CPU调度执行。

  • 核心价值:

    • 提升程序效率(如后台处理耗时任务,不阻塞主线程);

    • 增强用户体验(如界面交互与数据加载并行)。

  • 典型应用场景:

    • 2306购票系统(并发处理购票请求);

    • 消息通信、电商平台(订单处理、库存更新并行)。

二、Java线程创建方式

Java是通过 java.lang.Thread 类的对象来代表线程的。核心差异在于扩展性是否支持返回结果

创建方式 核心步骤 优点 缺点
继承Thread类 1. 子类继承Thread;
2. 重写run()(定义任务);
3. 创建对象调用start()启动
编码简单 无返回结果、无法继承其他类、扩展性差;
实现Runnable接口 1. 类实现Runnable;
2. 重写run();
3. 创建任务对象;
4. 对象传入Thread构造器,调用start()
扩展性强、可继承其他类、实现其他接口 无返回结果;需额外创建任务对象
Callable+FutureTask 1. 类实现Callable(T为返回值类型);
2. 重写call()(可抛异常);
3. 封装为线程任务对象FutureTask,传入Thread构造器;
4. 调用start()启动线程;
5. 用FutureTask.get()获取结果
扩展性强;支持返回任务结果 编码复杂、get()会阻塞

关键注意:仅start()能启动新线程(底层调用run());直接调用run()等同于普通方法,仍为单线程。

1. FutureTask核心API
构造器/方法 说明
public FutureTask<>(Callable call) 将Callable对象封装为FutureTask
public T get() throws Exception 获取call()方法的返回结果(阻塞等待)
2. 代码示例
// 1. 定义Callable任务类
class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        // 线程任务:模拟耗时操作
        Thread.sleep(1000);
        return "线程执行完成!结果:" + Thread.currentThread().getName();
    }
}

public class CallableTest {
    public static void main(String[] args) throws Exception {
        // 2. 封装为FutureTask
        FutureTask<String> task = new FutureTask<>(new MyCallable());
        // 3. 启动线程
        new Thread(task).start();
        // 4. 获取结果(阻塞直到任务完成)
        String result = task.get();
        System.out.println(result); // 输出:线程执行完成!结果:Thread-0
    }
}

三、Thread类常用方法与构造器

构造器 说明
public Thread(Runnable target) 封装Runnable任务对象为Thread线程对象
public Thread(String name) 创建线程并指定线程名称
public Thread(Runnable target, String name) 封装任务对象并指定线程名称
Thread 提供的常用方法 说明
public void run() 线程的任务方法
public void start() 启动线程
public String getName() 获取当前线程的名称,线程名称默认是 Thread-索引
public void setName(String name) 为线程设置名称
public static Thread currentThread() 获取当前执行的线程对象
public static void sleep(long time) 让当前执行的线程休眠指定毫秒后,再继续执行
public final void join()… 让调用该方法的线程先执行完毕

四、线程安全问题

多个线程同时操作同一共享资源且存在修改操作时,可能导致数据不一致或业务逻辑错误。

(一) 原因(三要素)

  1. 存在多个线程并发执行

  2. 线程共享同一资源

  3. 线程对共享资源有修改操作

(二) 线程同步方案(解决线程安全)

核心原理:加锁机制,保证同一时刻仅1个线程访问共享资源(临界区)。

同步方式 核心语法/实现 锁对象规则 优缺点对比
同步代码块 synchronized(锁对象) {
临界区代码
}
多线程必须用同一把锁;
实例方法用this
静态方法用类名.class
锁范围小(仅临界区),灵活性高;可读性稍差
同步方法 修饰符synchronized 返回值类型 方法名(形参列表) {
操作共享资源的核心代码
}
实例方法:默认锁this
静态方法:默认锁类名.class
可读性好;锁范围大(整个方法体),灵活性低
Lock锁(JDK5+) 用ReentrantLock实现:
1. 创建锁对象Lock lock = new ReentrantLock();
2. lock.lock()加锁;
3. finally中lock.unlock()释放
显式锁,无需默认锁对象 灵活性最高;需手动释放锁(避免死锁),编码稍复杂

五、线程通信

多个线程操作共享资源时,通过状态通知实现协调,避免无效资源争夺。

(一) 生产者-消费者模型

  • 生产者线程:生产数据后,自身等待,通知消费者;

  • 消费者线程:消费数据后,自身等待,通知生产者。

(二) 核心通信方法(Object类的方法)

需通过同步锁对象调用(与synchronized配合使用)。

方法 说明
void wait() 当前线程释放锁并进入无限等待,直到被其他线程notify()/notifyAll()唤醒
void notify() 唤醒当前锁对象上等待的单个线程
void notifyAll() 唤醒当前锁对象上等待的所有线程

六、线程池

定义:一种复用线程的技术(创建一批线程,反复使用,避免频繁创建/销毁的开销)。

无线程池的问题:

  • 频繁创建线程消耗CPU/内存

  • 大量线程会导致系统性能下降

(一) 工作原理

在这里插入图片描述

工作流程:

核心线程满 → 任务入队列 → 队列满 → 创建临时线程 → 临时线程满 → 触发拒绝策略

(二) 自定义线程池ThreadPoolExecutor

public ThreadPoolExecutor(
    int corePoolSize,          // 核心线程数(常驻,不销毁)
    int maximumPoolSize,       // 最大线程数(核心+临时)
    long keepAliveTime,        // 临时线程空闲存活时间
    TimeUnit unit,             // 存活时间单位(如TimeUnit.SECONDS)
    BlockingQueue<Runnable> workQueue, // 任务队列(队列满才创建临时线程)
    ThreadFactory threadFactory,       // 线程工厂(创建线程的工具,默认即可)
    RejectedExecutionHandler handler   // 任务拒绝策略(队列+最大线程满时触发)
)

临时线程创建时机与拒绝时机

  1. 临时线程创建:核心线程满 → 任务队列满 → 创建临时线程;

  2. 拒绝任务:核心线程满 → 任务队列满 → 临时线程满 → 触发拒绝策略。

(三) 任务拒绝策略

策略 说明
ThreadPoolExecutor.AbortPolicy 丢弃任务并抛RejectedExecutionException(默认策略)
ThreadPoolExecutor.DiscardPolicy 丢弃任务,不抛异常(不推荐)
ThreadPoolExecutor.DiscardOldestPolicy 丢弃队列中等待最久的任务,加入新任务
ThreadPoolExecutor.CallerRunsPolicy 由提交任务的主线程直接执行任务(避免丢弃)

(四) 核心接口 ExecutorService

方法 说明
void execute(Runnable command) 执行Runnable任务(无返回结果)
Future submit(Callable task) 执行Callable任务(返回Future对象,用于获取结果)
void shutdown() 等待所有任务执行完毕后关闭线程池(优雅关闭)
List shutdownNow() 立即关闭线程池,停止正在执行的任务,返回未执行的任务

(五) 工具类 Executors(不推荐用于大型系统)

方法 说明
Executors.newFixedThreadPool(int nThreads) 创建固定线程数的线程池(核心线程=最大线程,无临时线程)
Executors.newSingleThreadExecutor() 创建单线程线程池(仅1个核心线程)
Executors.newCachedThreadPool() 可缓存线程池(核心线程=0,临时线程无上限,空闲60s回收)
Executors.newScheduledThreadPool(int corePoolSize) 定时任务线程池(支持延迟/周期性执行)

陷进:

说明:tmp/198447094786_docxword_media_document_image_rId7.png

七、并发与并行

类别 定义 核心特点 适用场景
并发(Concurrency) CPU用时间片轮转调度线程,线程交替执行 同一时刻仅1个线程运行,用户感知“同时” 单核CPU处理多线程
并行(Parallelism) 多核CPU同时调度多个线程执行 真正“同时”运行,效率更高 多核CPU处理多线程

(一) 进程与线程的关系

  • 进程:正在运行的程序,是操作系统资源分配的基本单位(拥有独立内存、文件句柄等);

  • 线程:进程内的执行单元,是CPU调度的基本单位

  • 关联:一个进程可包含多个线程,线程共享进程的资源(内存、文件等),线程切换开销远小于进程。

八、线程生命周期

Java线程的6种状态定义在Thread.State枚举中,状态转换是线程从创建到销毁的完整过程。

状态 说明
NEW(新建) 线程对象已创建,但未调用start()(未启动)
RUNNABLE(可运行) 线程已调用start(),等待CPU调度(包含“就绪”和“运行中”)
BLOCKED(锁阻塞) 线程竞争锁失败,进入阻塞状态(获取锁后转为RUNNABLE)
WAITING(无限等待) 线程调用wait()/join()等方法,释放锁并无限等待(需其他线程唤醒)
TIMED_WAITING(计时等待) 线程调用sleep(long)/wait(long)等方法,释放锁并等待指定时间(时间到或被唤醒后转为RUNNABLE)
TERMINATED(被终止) 线程run()方法执行完毕或因未捕获异常终止(生命周期结束,不可重启)

核心状态转换流程

NEW →(start())→ RUNNABLE →(竞争锁失败)→ BLOCKED →(获取锁)→ RUNNABLE
RUNNABLE →(调用wait())→ WAITING →(notify()/notifyAll())→ RUNNABLE
RUNNABLE →(调用sleep(long))→ TIMED_WAITING →(时间到/notify())→ RUNNABLE
RUNNABLE →(run()执行完/异常)→ TERMINATED
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐