Thread

吴书松
吴书松
发布于 2026-04-07 / 0 阅读
0
0

Thread

1. 基本概念

1.1 Thread(线程)

  • Thread 是 Java 中执行任务的载体,它代表一个操作系统线程的实例。

  • 通过继承 Thread 类并重写 run() 方法,可以定义线程要执行的任务。

  • 缺点:继承方式导致无法再继承其他类;频繁创建和销毁线程开销大。

1.2 Runnable(可运行任务)

  • 一个函数式接口,仅包含 void run() 方法,不返回结果,也不能抛出受检异常。

  • 任务是无返回值的,适合单纯的执行操作。

  • 可以通过 new Thread(runnable).start() 或提交给线程池执行。

1.3 Callable(可调用任务)

  • 一个函数式接口,包含 V call() throws Exception 方法,可返回结果并能抛出异常。

  • 任务有返回值(通过 Future 获取),更适合需要异步计算结果或处理异常的场景。

  • 通常与 ExecutorServiceFuture 搭配使用。

1.4 线程池(Thread Pool)

  • 一种管理和复用线程的机制,例如 ThreadPoolExecutor

  • 避免频繁创建/销毁线程的开销,控制并发线程数量,提供任务排队、拒绝策略等能力。

  • 核心接口是 ExecutorService,常用工厂类 Executors 创建。

2. 它们之间的关系

text

任务(Runnable / Callable)  --->  线程池(ExecutorService)  --->  工作线程(Thread)
  • RunnableCallable 描述“做什么”(任务逻辑)。

  • Thread 是“谁来做”(执行任务的实体),但现代开发中很少直接操作 Thread

  • 线程池 则是“如何高效地安排谁来做”(任务调度 + 线程生命周期管理)。

2.1 典型组合方式

组合

说明

Thread + Runnable

传统方式:new Thread(runnable).start()

Thread + Callable

不直接支持,因为 Thread 构造器不接受 Callable

线程池 + Runnable

executor.execute(runnable)submit(runnable)

线程池 + Callable

executor.submit(callable) 返回 Future

2.2 代码示例

java

// Runnable 任务
Runnable task = () -> System.out.println("Hello Runnable");

// Callable 任务
Callable<Integer> calc = () -> { 
    Thread.sleep(1000);
    return 42;
};

// 线程池
ExecutorService pool = Executors.newFixedThreadPool(2);

// 提交 Runnable(无返回值)
pool.execute(task);

// 提交 Callable(有返回值)
Future<Integer> future = pool.submit(calc);
Integer result = future.get(); // 阻塞获取结果

pool.shutdown();

3. 核心区别总结

特性

Thread

Runnable

Callable

线程池

本质

线程对象

任务接口

任务接口

线程管理容器

是否有返回值

无(run方法void)

有(call方法返回V)

能否抛异常

不能(run不抛)

不能

能(throws Exception)

-

是否复用线程

不复用,用完销毁

配合池可复用

配合池可复用

核心价值:复用线程

使用场景

简单并发,不推荐

无返回值的任务

有返回值的异步任务

生产环境首选

4. 补充:Future 与 Callable 的绑定

Callable 通常与 Future 一起工作,Future 代表异步计算的结果,提供:

  • get() 阻塞获取结果

  • cancel() 取消任务

  • isDone() 检查是否完成

5. 实践建议

  • 避免直接使用 Thread,除非写教学代码或极简场景。

  • 优先使用线程池 + Runnable/Callable,充分利用复用和资源控制。

  • 需要返回值或异常处理时选 Callable,否则用 Runnable

  • 线程池推荐使用 ThreadPoolExecutor 构造器(而不是 Executors 工厂),以便明确设置队列、拒绝策略等参数,防止资源耗尽。

package com.wss.wssdemo.config;

import lombok.Getter;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;

import java.util.concurrent.*;

public class CustomThreadPool {

    // 获取CPU核心数(用于调整线程数量)
    private static final int CPU_CORES = Runtime.getRuntime().availableProcessors();

    // 任务类型:根据实际场景调整
    // - IO密集型(如网络调用、文件读写):线程数可设为 CPU_CORES * 2
    // - CPU密集型(如计算):线程数设为 CPU_CORES + 1
    private static final int CORE_POOL_SIZE = CPU_CORES;            // 核心线程数
    private static final int MAX_POOL_SIZE = CPU_CORES * 2;         // 最大线程数
    private static final long KEEP_ALIVE_TIME = 60L;                // 空闲线程存活时间
    private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS;     // 时间单位
    private static final int QUEUE_CAPACITY = 100;                  // 有界队列容量

    // 创建线程池(使用CallerRunsPolicy拒绝策略)
    private static final ThreadPoolExecutor THREAD_POOL = new ThreadPoolExecutor(
            CORE_POOL_SIZE,
            MAX_POOL_SIZE,
            KEEP_ALIVE_TIME,
            TIME_UNIT,
            new LinkedBlockingQueue<>(QUEUE_CAPACITY),   // 有界队列,防止内存溢出
            new ThreadPoolExecutor.CallerRunsPolicy()    // 队列满且线程数达上限时,由调用者线程执行
    );

    @Getter
    private static Scheduler scheduler = Schedulers.fromExecutor(CustomThreadPool.getThreadPool());;

    /**
     * 获取线程池实例
     */
    public static ExecutorService getThreadPool() {
        return THREAD_POOL;
    }

    /**
     * 优雅关闭线程池(可选)
     */
    public static void shutdown() {
        THREAD_POOL.shutdown();
        try {
            if (!THREAD_POOL.awaitTermination(60, TimeUnit.SECONDS)) {
                THREAD_POOL.shutdownNow();
            }
        } catch (InterruptedException e) {
            THREAD_POOL.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}


评论