Java 并发编程创建线程的四种方式示例详解

 更新时间:2025年09月02日 11:25:09   作者:钟琛  
本文对比Java创建线程的四种方式:继承Thread类(单继承限制)、实现Runnable接口(灵活推荐)、实现Callable接口(支持返回值)、使用线程池(最佳实践,资源管理高效),推荐优先使用线程池提升系统稳定性与资源利用率,感兴趣的朋友一起看看吧

1. 继承 Thread 类

特点

  • 直接继承 Thread 类
  • 重写 run() 方法
  • 启动线程调用 start() 方法
  • 缺点:Java 单继承限制,不够灵活
class MyThread extends Thread {
    @Override
    public void run() {
        // 线程执行逻辑
        System.out.println("继承Thread类的线程: " + Thread.currentThread().getName());
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 启动线程
    }
}

2. 实现 Runnable 接口(推荐)

特点

  • 实现 Runnable 接口
  • 线程与任务解耦
  • 可复用同一个任务对象
  • 支持 Lambda 表达式简化代码
  • 优点:避免单继承限制,更灵活
public class RunnableDemo {
    public static void main(String[] args) {
        // 方式1:匿名内部类
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable匿名内部类线程: " + Thread.currentThread().getName());
            }
        }).start();
        // 方式2:Lambda表达式(推荐)
        new Thread(() -> {
            System.out.println("Runnable Lambda线程: " + Thread.currentThread().getName());
        }).start();
        // 方式3:实现类
        Runnable task = new MyRunnable();
        new Thread(task).start();
    }
}
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("实现Runnable接口的线程: " + Thread.currentThread().getName());
    }
}

3. 实现 Callable 接口(带返回值)

特点

  • 实现 Callable 接口
  • 可返回执行结果(通过 FutureTask
  • 可抛出受检异常
  • 配合 FutureTask 获取结果
  • 适用场景:需要获取异步任务结果的场景
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建Callable任务
        Callable<String> callableTask = () -> {
            Thread.sleep(1000);
            return "Callable线程执行结果: " + Thread.currentThread().getName();
        };
        // 包装为FutureTask
        FutureTask<String> futureTask = new FutureTask<>(callableTask);
        // 启动线程
        new Thread(futureTask).start();
        // 获取结果(会阻塞直到任务完成)
        String result = futureTask.get();
        System.out.println(result);
    }
}

4. 使用线程池(最佳实践)

特点

  • 使用 ExecutorService 管理线程
  • 避免频繁创建销毁线程的开销
  • 提供任务队列和线程复用
  • 支持两种任务提交方式:
    • execute():提交 Runnable 任务
    • submit():提交 Callable 任务,返回 Future
  • 最佳实践:生产环境推荐使用
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadPoolDemo {
    public static void main(String[] args) throws Exception {
        // 创建固定大小线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        // 提交Runnable任务
        executor.execute(() -> {
            System.out.println("线程池执行Runnable任务: " + Thread.currentThread().getName());
        });
        // 提交Callable任务
        Future<String> future = executor.submit(() -> {
            Thread.sleep(500);
            return "线程池执行Callable任务结果: " + Thread.currentThread().getName();
        });
        // 获取Callable结果
        System.out.println(future.get());
        // 关闭线程池
        executor.shutdown();
    }
}

5.四种方式对比

创建方式返回值异常处理资源消耗灵活性推荐指数
继承 Thread受限于重写⭐☆☆☆
实现 Runnable自由处理⭐⭐⭐☆
实现 Callable自由处理⭐⭐⭐⭐
线程池统一管理极高⭐⭐⭐⭐⭐

6.线程池的进阶用法

自定义线程池

import java.util.concurrent.*;
public class CustomThreadPool {
    public static void main(String[] args) {
        // 创建自定义线程池
        ExecutorService customPool = new ThreadPoolExecutor(
            4, // 核心线程数
            10, // 最大线程数
            60, // 空闲线程存活时间
            TimeUnit.SECONDS, // 时间单位
            new ArrayBlockingQueue<>(100), // 任务队列
            Executors.defaultThreadFactory(), // 线程工厂
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
        );
        // 提交任务
        for (int i = 0; i < 20; i++) {
            int taskId = i;
            customPool.execute(() -> {
                System.out.println("执行任务 " + taskId + " 线程: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }
        // 优雅关闭
        customPool.shutdown();
        try {
            if (!customPool.awaitTermination(60, TimeUnit.SECONDS)) {
                customPool.shutdownNow();
            }
        } catch (InterruptedException e) {
            customPool.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }
}

线程池关键参数解析

参数说明
核心线程数线程池长期维持的线程数
最大线程数线程池允许的最大线程数
空闲存活时间非核心线程空闲超过此时间将被回收
任务队列存放待执行任务的阻塞队列
线程工厂用于创建新线程,可自定义线程名称、优先级等
拒绝策略当任务太多时的处理策略(Abort-抛异常, Discard-丢弃, CallerRuns-调用者执行)

四种拒绝策略对比

策略行为
AbortPolicy默认策略,抛出 RejectedExecutionException
DiscardPolicy静默丢弃新任务
DiscardOldestPolicy丢弃队列中最老的任务,然后重试提交
CallerRunsPolicy由调用者线程(提交任务的线程)直接执行该任务

实践建议

  • 优先选择线程池
    • 资源利用率高
    • 避免线程创建销毁开销
    • 提供更好的系统稳定性
  • 避免直接创建线程
  • // 不推荐
    new Thread(() -> {...}).start();
    
    // 推荐使用线程池
    executor.execute(() -> {...});
  • 合理配置线程池参数
    • CPU 密集型任务:线程数 ≈ CPU 核数
    • IO 密集型任务:线程数 ≈ CPU 核数 * (1 + 平均等待时间/平均计算时间)
    • CPU密集型任务:较小队列(避免任务堆积)
    • IO密集型任务:较大队列(充分利用CPU)
  • 使用合适的任务类型
    • 不需要返回值:Runnable + execute()
    • 需要返回值:Callable + submit()
  • 正确处理线程池关闭
    • shutdown():停止接收新任务,处理队列中任务
    • shutdownNow():尝试中断所有任务
    • awaitTermination():等待线程池完全终止

7.线程池任务处理流程图

最大处理能力 = 核心线程数 + 任务队列容量 + (最大线程数 - 核心线程数)

 任务的执行顺序不一定与提交顺序一致

举个例子(假设任务执行时间较长,核心线程一直被任务1,任务2占用):核心线程数是2,最大线程数是10,任务队列长5;那么最大处理能力为15(2+5+8),第16个任务执行拒绝策略,任务3会在任务队列里排队,而任务8在发现核心线程都在工作时且任务队列已满,但线程数小于最大线程的情况下,会创建非核心线程,并直接开始执行任务8,所以说任务8会比任务3更快执行,因此任务的执行顺序不一定与提交顺序一致

到此这篇关于Java 并发编程:创建线程的 4 种方式的文章就介绍到这了,更多相关java创建线程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot应用中静态资源访问与接口请求冲突问题解决

    springboot应用中静态资源访问与接口请求冲突问题解决

    这篇文章主要介绍了springboot应用中静态资源访问与接口请求冲突,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • Java并发编程之Executors类详解

    Java并发编程之Executors类详解

    今天给大家带来的是关于Java并发编程的相关知识,文章围绕着Java Executors类展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • startActivityForResult和setResult案例详解

    startActivityForResult和setResult案例详解

    这篇文章主要介绍了startActivityForResult和setResult案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Java连接Mysql数据库详细代码实例

    Java连接Mysql数据库详细代码实例

    这篇文章主要介绍了Java连接Mysql数据库详细代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • JSqlParse完整介绍

    JSqlParse完整介绍

    JSqlParse是一款很精简的sql解析工具,本文主要介绍了JSqlParse完整介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-05-05
  • Spring的@Validation和javax包下的@Valid区别以及自定义校验注解

    Spring的@Validation和javax包下的@Valid区别以及自定义校验注解

    这篇文章主要介绍了Spring的@Validation和javax包下的@Valid区别以及自定义校验注解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • 举例解析Java的设计模式编程中里氏替换原则的意义

    举例解析Java的设计模式编程中里氏替换原则的意义

    这篇文章主要介绍了Java的设计模式中里氏替换原则的意义,文中举例来说明里氏替换原则中强调的继承特性方面可能带来的问题,需要的朋友可以参考下
    2016-02-02
  • Java实现读取CSV文件并将数据放入对象

    Java实现读取CSV文件并将数据放入对象

    CSV文件是一种常见的数据存储格式,广泛应用于数据交换,日志记录和表格数据处理,在Java开发中,读取CSV文件并将数据映射到对象中是常见的需求,本文将详细介绍几种常见方法,有需要的可以了解下
    2025-06-06
  • java+SpringBoot设计实现评教系统

    java+SpringBoot设计实现评教系统

    这篇文章主要介绍了用过Java SpringBoot实现一个简单的评价系统,可以做到学生管理、教师管理、评教管理、指标管理、课程管理等。感兴趣的可以了解一下
    2021-12-12
  • springboot3.0整合mybatis-flex实现逆向工程的示例代码

    springboot3.0整合mybatis-flex实现逆向工程的示例代码

    逆向工程先创建数据库表,由框架负责根据数据库表,自动生成mybatis所要执行的代码,本文就来介绍一下springboot mybatis-flex逆向工程,感兴趣的可以了解一下
    2024-06-06

最新评论