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创建线程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java 异步回调机制实例分析

    Java 异步回调机制实例分析

    这篇文章主要介绍了Java 异步回调机制实例解析的相关资料,需要的朋友可以参考下
    2017-02-02
  • Java工具之ja-netfilter 2022.1 配置教程

    Java工具之ja-netfilter 2022.1 配置教程

    这篇文章主要介绍了Java工具之ja-netfilter 2022.1 配置教程,本防火墙基于javaagent,所以目前只有基于java的程序能够使用,需要的朋友可以参考下
    2022-04-04
  • java设计模式之组合模式(Composite)

    java设计模式之组合模式(Composite)

    这篇文章主要为大家详细介绍了java设计模式之组合模式Composite,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • SpringBoot异步调用相同类的解决方案

    SpringBoot异步调用相同类的解决方案

    在SpringBoot中,同一个类中调用带有@Async注解的方法时,异步调用会失效,因为直接通过this调用方法时,并没有通过Spring的代理对象,下面给大家分享SpringBoot异步调用相同类的解决方案,感兴趣的朋友一起看看吧
    2025-02-02
  • 浅谈spring-boot 允许接口跨域并实现拦截(CORS)

    浅谈spring-boot 允许接口跨域并实现拦截(CORS)

    本篇文章主要介绍了浅谈spring-boot 允许接口跨域并实现拦截(CORS),具有一定的参考价值,有兴趣的可以了解一下
    2017-08-08
  • SpringCloud服务的平滑上下线的方法

    SpringCloud服务的平滑上下线的方法

    这篇文章主要介绍了SpringCloud服务的平滑上下线的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-06-06
  • Jenkins+Git+Maven自动化部署配置详解

    Jenkins+Git+Maven自动化部署配置详解

    本文主要介绍了Jenkins+Git+Maven自动化部署配置详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • Java OpenCV图像处理之SIFT角点检测详解

    Java OpenCV图像处理之SIFT角点检测详解

    SIFT,即尺度不变特征变换,是用于图像处理领域的一种描述。这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子。本文将详细介绍一下Java OpenCV图像处理中的SIFT角点检测,需要的可以参考一下
    2022-02-02
  • 解析Runtime中shutdown hook的使用详解

    解析Runtime中shutdown hook的使用详解

    本篇文章是对解析Runtime中shutdown hook的使用进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • Java Spring动态生成Mysql存储过程详解

    Java Spring动态生成Mysql存储过程详解

    这篇文章主要介绍了Java Spring动态生成Mysql存储过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06

最新评论