线程的三种创建方式与生命周期及线程池

一.线程的三种创建方式与生命周期

1. 三种创建方式

方式一:继承 Thread(不推荐,单继承限制)

typescript 复制代码
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " 运行");
    }

    public static void main(String[] args) {
        new MyThread().start();
    }
}

方式二:实现 Runnable(推荐,解耦任务和线程)

typescript 复制代码
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " 运行");
    }

    public static void main(String[] args) {
        new Thread(new MyRunnable()).start();
    }
}

方式三:实现 Callable + FutureTask(带返回值,推荐)

arduino 复制代码
public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        return "任务完成";
    }

    public static void main(String[] args) throws Exception {
        FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
        new Thread(futureTask).start();
        
        // 阻塞获取结果
        String result = futureTask.get();
        System.out.println(result);
    }
}

实际开发中优先用 Runnable / Callable ,配合线程池使用,不要直接 new Thread()


2. 线程六种状态

表格

状态 触发条件
NEW 刚创建,未调用 start()
RUNNABLE 调用 start(),等待或正在运行
BLOCKED 等待监视器锁(synchronized)
WAITING 无限期等待,如 wait()join()
TIMED_WAITING 限时等待,如 sleep(1000)wait(1000)
TERMINATED 执行完毕或异常退出

代码查看状态:

scss 复制代码
Thread t = new Thread(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});
System.out.println(t.getState()); // NEW
t.start();
System.out.println(t.getState()); // RUNNABLE / TIMED_WAITING

3. 常用方法速查

表格

方法 作用
start() 启动线程,进入 RUNNABLE
run() 直接调用不会启动新线程,只是普通方法执行
sleep(ms) 当前线程休眠,不释放锁
yield() 让出 CPU,进入就绪态,下次调度可能还是它
join() 等待该线程执行完,再执行当前线程
interrupt() 打断线程,配合 isInterrupted()InterruptedException 使用

二.线程池 ThreadPoolExecutor

1. 为什么要用线程池?

  • 减少线程创建/销毁的开销
  • 控制并发线程数量
  • 便于线程管理和复用

2. 七大核心参数

arduino 复制代码
public ThreadPoolExecutor(
    int corePoolSize,           // 核心线程数(常驻)
    int maximumPoolSize,        // 最大线程数
    long keepAliveTime,         // 非核心线程空闲存活时间
    TimeUnit unit,              // 时间单位
    BlockingQueue<<Runnable> workQueue,  // 任务等待队列
    ThreadFactory threadFactory,        // 线程工厂(自定义线程名)
    RejectedExecutionHandler handler    // 拒绝策略
)

执行流程

  1. 任务进来,当前运行线程 < corePoolSize:创建新线程执行任务
  2. 当前运行线程 ≥ corePoolSize:任务进入 workQueue
  3. 队列满了,且运行线程 < maximumPoolSize:创建临时线程(非核心)执行任务
  4. 运行线程 ≥ maximumPoolSize:触发拒绝策略

3. 四种拒绝策略

表格

策略 行为
AbortPolicy(默认) 直接抛异常 RejectedExecutionException
CallerRunsPolicy 由调用线程(提交任务的线程)自己执行
DiscardPolicy 静默丢弃任务,不抛异常
DiscardOldestPolicy 丢弃队列最老的任务,重试提交

4. 自定义线程池(生产环境推荐)

不要用 Executors 创建线程池! FixedThreadPoolSingleThreadPool 的队列是 LinkedBlockingQueue,允许长度无限,会导致 OOM。

csharp 复制代码
public class ThreadPoolConfig {
    
    public static ThreadPoolExecutor createPool() {
        return new ThreadPoolExecutor(
            4,                              // 核心线程数:CPU密集型 = CPU核数,IO密集型 = 2*CPU核数
            8,                              // 最大线程数
            60L,                            // 空闲线程存活时间
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(100),   // 有界队列!防止 OOM
            new ThreadFactoryBuilder().setNameFormat("order-pool-%d").build(), // Guava 工具
            new ThreadPoolExecutor.CallerRunsPolicy() // 满了就让提交者自己跑,起到限流效果
        );
    }
}

提交任务:

ini 复制代码
ThreadPoolExecutor pool = ThreadPoolConfig.createPool();

// 无返回值
pool.execute(() -> System.out.println("执行任务"));

// 有返回值
Future<Integer> future = pool.submit(() -> {
    return 1 + 1;
});
Integer result = future.get(); // 阻塞获取

5. 优雅关闭

scss 复制代码
pool.shutdown();           // 平滑关闭,等待任务执行完
pool.awaitTermination(30, TimeUnit.SECONDS); // 最多等30秒
pool.shutdownNow();        // 立即关闭,返回未执行的任务列表
相关推荐
Rust研习社12 小时前
MSRV 是什么?一文说清楚
后端·rust·编程语言
XovH12 小时前
Docker 网络进阶:容器间通信与 DNS 解析
后端
月読h12 小时前
Hermes QQbot websocket Problems
后端
Byron__12 小时前
SpringBoot 核心面试知识点(自动配置/启动流程/注解/Starter)
spring boot·后端·面试
程序员cxuan12 小时前
这个插件,直接让 Java 小白秒变资深开发
人工智能·后端·程序员
ZengLiangYi13 小时前
Prompt 工程:让 LLM 输出结构化 JSON
前端·javascript·后端
Oo_行者_oO13 小时前
MyBatis-Plus 字段数学计算封装
后端
bandaoyu13 小时前
【AMD】HDP(Host Data Path)是什么
java·后端·spring