Java中创建线程的几种方式

目录

Java 创建线程的几种方式

一、继承 Thread 类

核心原理

实现步骤

代码示例

简化写法(Lambda 表达式)

优缺点

二、实现 Runnable 接口

核心原理

实现步骤

代码示例

简化写法(Lambda 表达式)

优缺点分析

三、实现 Callable 接口

核心原理

实现步骤

代码示例

简化写法(Lambda 表达式)

优缺点分析

四、使用线程池

核心原理

线程池的 7 个核心参数

常见拒绝策略

线程池的使用步骤

代码示例

注意事项

总结对比


Java 创建线程的几种方式

在 Java 中,创建线程主要有 4 种经典方式:继承 Thread 类实现 Runnable 接口实现 Callable 接口使用线程池。本文将结合原理分析、代码示例和场景对比,系统讲解这四种方式的实现细节与差异。

一、继承 Thread 类

核心原理

Thread类是 Java 线程的核心基类,通过继承Thread并重写其run()方法(定义线程执行逻辑),即可创建一个自定义线程。启动线程需调用start()方法(而非直接调用run(),否则会退化为普通方法调用)。

实现步骤

  1. 自定义类继承Thread
  2. 重写run()方法(线程的核心执行逻辑);
  3. 创建自定义类实例,调用start()启动线程。

代码示例

public class ThreadTest1 {public static void main(String[] args) {// 创建并启动线程Thread t = new MyThread();t.start();  // 主线程逻辑for (int i = 1; i <= 5; i++) {System.out.println("主线程main输出:" + i);}}
}// 自定义线程类(继承Thread)
class MyThread extends Thread {@Overridepublic void run() {// 线程执行逻辑for (int i = 1; i <= 5; i++) {System.out.println("子线程MyThread输出:" + i);}}
}

简化写法(Lambda 表达式)

public class CreateThread1 {public static void main(String[] args) {// 使用Lambda表达式直接定义线程逻辑Thread t1 = new Thread(() -> {System.out.println("子线程输出");});t1.start();}
}

优缺点

  • 优点:实现简单,直接操作线程对象;
  • 缺点:Java 单继承限制(若已继承其他类则无法使用);

二、实现 Runnable 接口

核心原理

Runnable是一个函数式接口(仅含run()方法),通过实现该接口定义线程任务(逻辑),再将任务交给Thread对象执行。这种方式将 “线程任务” 与 “线程对象” 解耦,更符合面向对象设计。

实现步骤

  1. 自定义类实现Runnable接口;
  2. 重写run()方法(定义任务逻辑);
  3. 创建任务实例,通过new Thread(runnable)绑定到线程对象;
  4. 调用start()启动线程。

代码示例

public class ThreadTest2 {public static void main(String[] args) {// 创建任务对象Runnable target = new MyRunnable();// 绑定线程并启动new Thread(target).start();// 主线程逻辑for (int i = 1; i <= 5; i++) {System.out.println("主线程main输出 ===》" + i);}}
}// 自定义任务类(实现Runnable)
class MyRunnable implements Runnable {@Overridepublic void run() {// 任务执行逻辑for (int i = 1; i <= 5; i++) {System.out.println("子线程输出 ===》" + i);}}
}

简化写法(Lambda 表达式)

public class CreateThread2 {public static void main(String[] args) {// Lambda直接定义任务逻辑Thread t1 = new Thread(() -> System.out.println("子线程输出"));t1.start();System.out.println("主线程输出");}
}

优缺点分析

  • 优点:避免单继承限制;任务与线程解耦,灵活性高;
  • 缺点:无法直接获取线程执行结果(需结合其他机制)。

三、实现 Callable 接口

核心原理

Callable接口(Java 1.5 引入)与Runnable类似,但支持返回线程执行结果抛出检查异常。需通过FutureTask(实现了RunnableFuture接口)将Callable任务封装为可执行对象,再交给Thread执行。FutureTask支持通过get()方法获取线程结果(阻塞等待)。

实现步骤

  1. 自定义类实现Callable接口(指定返回值类型);
  2. 重写call()方法(定义带返回值的任务逻辑);
  3. 创建Callable实例,通过FutureTask封装;
  4. FutureTask交给Thread启动;
  5. 调用FutureTask.get()获取结果(阻塞等待线程完成)。

代码示例

// 自定义Callable任务(计算1到n的和)
class MyCallable implements Callable<String> {private int n;public MyCallable(int n) {this.n = n;}@Overridepublic String call() throws Exception {int sum = 0;for (int i = 1; i <= n; i++) {sum += i;}return "线程求出了1-" + n + "的和是:" + sum;}
}public class ThreadTest3 {public static void main(String[] args) throws Exception {// 创建Callable任务Callable<String> call1 = new MyCallable(100);Callable<String> call2 = new MyCallable(200);// 封装为FutureTaskFutureTask<String> f1 = new FutureTask<>(call1);FutureTask<String> f2 = new FutureTask<>(call2);// 启动线程new Thread(f1).start();new Thread(f2).start();// 获取结果(阻塞等待)System.out.println(f1.get());  // 输出:线程求出了1-100的和是:5050System.out.println(f2.get());  // 输出:线程求出了1-200的和是:20100}
}

简化写法(Lambda 表达式)

public class CreateThread3 {public static void main(String[] args) throws Exception {// Lambda直接定义Callable逻辑FutureTask<String> futureTask = new FutureTask<>(() -> "hello, Callable");Thread t1 = new Thread(futureTask);t1.start();// 获取线程结果System.out.println("子线程返回的结果:" + futureTask.get());  // 输出:hello, Callable}
}

优缺点分析

  • 优点:支持返回值和异常抛出;适合需要异步计算结果的场景;
  • 缺点:需结合FutureTask使用,实现略复杂;get()方法可能阻塞主线程。

四、使用线程池

核心原理

线程池(ThreadPoolExecutor)是 Java 并发包(java.util.concurrent)提供的线程管理工具,通过复用线程避免频繁创建 / 销毁线程的开销,提高性能和稳定性。线程池支持统一管理线程的创建、调度和监控。

线程池的 7 个核心参数

使用ThreadPoolExecutor构造函数时需指定以下参数:

参数说明
corePoolSize核心线程数(长期保留的活跃线程数)
maximumPoolSize最大线程数(线程池允许的最大线程数)
keepAliveTime非核心线程的空闲存活时间(超时后销毁)
unitkeepAliveTime的时间单位(如TimeUnit.SECONDS
workQueue任务队列(存储待执行的任务,如ArrayBlockingQueue
threadFactory线程工厂(用于创建线程,默认Executors.defaultThreadFactory()
handler拒绝策略(任务队列和线程池均满时的处理方式)

常见拒绝策略

  • AbortPolicy(默认):直接抛出RejectedExecutionException
  • DiscardPolicy:丢弃新任务,不报错;
  • DiscardOldestPolicy:丢弃队列中最旧的任务,尝试重新提交新任务;
  • CallerRunsPolicy:由调用线程(如主线程)直接执行任务。

线程池的使用步骤

  1. 初始化ThreadPoolExecutor(指定核心参数);
  2. 通过submit()execute()提交任务(submit()支持返回Future);
  3. 任务执行完毕后,调用shutdown()shutdownNow()关闭线程池。

代码示例

import java.util.concurrent.*;public class CreateThread4 {public static void main(String[] args) throws Exception {// 初始化线程池(核心参数示例)ThreadPoolExecutor pool = new ThreadPoolExecutor(2,               // 核心线程数:25,               // 最大线程数:510,              // 空闲存活时间:10TimeUnit.SECONDS, // 时间单位:秒new ArrayBlockingQueue<>(3),  // 任务队列:容量3的阻塞队列Executors.defaultThreadFactory(),  // 默认线程工厂new ThreadPoolExecutor.AbortPolicy()  // 拒绝策略:直接报错);// 提交任务(支持返回Future)Future<String> future = pool.submit(() -> {System.out.println("子线程执行任务");return "任务执行完成";});// 获取任务结果(阻塞等待)System.out.println("子线程返回的结果:" + future.get());  // 输出:任务执行完成// 关闭线程池(不再接受新任务,等待现有任务完成)pool.shutdown();}
}

注意事项

  • 合理配置参数:根据任务类型(CPU 密集型 / IO 密集型)调整核心线程数和队列容量;
  • 正确关闭线程池:避免调用shutdownNow()(可能强制终止未完成任务);
  • 监控与调优:通过getActiveCount()getQueue().size()等方法监控线程池状态,优化参数配置。

总结对比

方式核心接口 / 类是否支持返回值优点适用场景
继承 Thread 类Thread实现简单简单任务,无继承冲突场景
实现 Runnable 接口Runnable解耦任务与线程,避免单继承限制多线程共享任务逻辑
实现 Callable 接口Callable+FutureTask支持返回值和异常,适合异步计算需要获取线程执行结果的场景
使用线程池ThreadPoolExecutor是(通过submit复用线程,降低开销,便于管理高并发、长期运行的任务

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/80926.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Git] 基本操作及用户配置

文章目录 现在所讲&#xff0c;全部是本地Git仓库&#xff0c;不是远程仓库&#xff01;Git是版本控制工具&#xff0c;而并非只能用远程仓库的版本控制工具&#xff01; 什么是“仓库”&#xff08;Repository&#xff09;&#xff1f;创建一个 Git 本地仓库&#xff1a;git i…

layui 介绍

layui&#xff08;谐音&#xff1a;类 UI) 是一套开源的 Web UI 解决方案&#xff0c;采用自身经典的模块化规范&#xff0c;并遵循原生 HTML/CSS/JS 的开发方式&#xff0c;极易上手&#xff0c;拿来即用。其风格简约轻盈&#xff0c;而组件优雅丰盈&#xff0c;从源代码到使用…

笔记:NAT

一、NAT 的基本概念 NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09; 是一种在 IP 网络中重新映射 IP 地址的技术&#xff0c;主要用于解决 IPv4 地址短缺问题&#xff0c;同时提供一定的网络安全防护作用。 功能&#xff1a; 将内部网络&am…

cursor/vscode启动项目connect ETIMEDOUT 127.0.0.1:xx

现象&#xff1a; 上午正常使用cursor/vscode&#xff0c;因为需要写前端安装了nodejs16.20和vue2&#xff0c;结果下午启动前端服务无法访问&#xff0c;浏览器一直转圈。接着测试运行最简单的flask服务&#xff0c;vscode报错connect ETIMEDOUT 127.0.0.1:xx&#xff0c;要么…

EXO分布式部署deepseek r1

EXO 是一个支持分布式 AI 计算的框架&#xff0c;可以用于在多个设备&#xff08;包括 Mac Studio&#xff09;上运行大语言模型&#xff08;LLM&#xff09;。以下是联调 Mac Studio 512GB 的步骤&#xff1a; 安装 EXO • 从 EXO GitHub 仓库 下载源码或使用 git clone 获取…

python训练营打卡第30天

模块和库的导入 知识点回顾&#xff1a; 导入官方库的三种手段导入自定义库/模块的方式导入库/模块的核心逻辑&#xff1a;找到根目录&#xff08;python解释器的目录和终端的目录不一致&#xff09; 一、导入官方库 1.标准导入&#xff1a;导入整个库 import mathprint(&quo…

Unity 多时间源Timer定时器实战分享:健壮性、高效性、多线程安全与稳定性能全面解析

简介 Timer 是一个 Unity 环境下高效、灵活的定时任务调度系统&#xff0c;支持以下功能&#xff1a; •支持多种时间源&#xff08;游戏时间 / 非缩放时间 / 真实时间&#xff09; •支持一次性延迟执行和重复执行 •提供 ID、回调、目标对象等多种查询和销毁方式 •内建…

深入理解Docker和K8S

深入理解Docker和K8S Docker 是大型架构的必备技能&#xff0c;也是云原生核心。Docker 容器化作为一种轻量级的虚拟化技术&#xff0c;其核心思想&#xff1a;将应用程序及其所有依赖项打包在一起&#xff0c;形成一个可移植的单元。 容器的本质是进程&#xff1a; 容器是在…

docker中使用openresty

1.为什么要使用openresty 我这边是因为要使用1Panel&#xff0c;第一个最大的原因&#xff0c;就是图方便&#xff0c;比较可以一键安装。但以前一直都是直接安装nginx。所以需要一个过度。 2.如何查看openResty使用了nginx哪个版本 /usr/local/openresty/nginx/sbin/nginx …

CSS【详解】弹性布局 flex

适用场景 一维&#xff08;行或列&#xff09;布局 基本概念 包裹所有被布局元素的父元素为容器 所有被布局的元素为项目 项目的排列方向&#xff08;垂直/水平&#xff09;为主轴 与主轴垂直的方向交交叉轴 容器上启用 flex 布局 将容器的 display 样式设置为 flex 或 i…

全能视频处理工具介绍说明

软件介绍 本文介绍的软件是FFmpeg小白助手&#xff0c;它是一款视频处理工具。 使用便捷性 这款FFmpeg小白助手无需安装&#xff0c;解压出来就能够直接投入使用。 主要功能概述 该工具主要具备格式转换、文件裁剪、文件压缩、文件合并这四大功能。 格式转换能力 软件支持…

Linux中的DNS的安装与配置

DNS简介 DNS&#xff08;DomainNameSystem&#xff09;是互联网上的一项服务&#xff0c;它作为将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便的访问互联网。 DNS使用的是53端口 通常DNS是以UDP这个较快速的数据传输协议来查询的&#xff0c;但是没有查…

tshark的使用技巧(wireshark的命令行,类似tcpdump):转换格式,设置filter

tshark的使用技巧&#xff08;wireshark的命令行&#xff0c;类似tcpdump&#xff09;&#xff1a;转换格式&#xff0c;设置filter tshark一般在 C:\Program Files\Wireshark 使用管理员权限 打开cmd tshark -D 列出支持抓包的接口&#xff1a; c:\Program Files\Wiresh…

vscode打开的文件被覆盖/只能打开两个文件(Visual Studio Code)

vscode打开的文件被覆盖/只能打开两个文件&#xff08;Visual Studio Code&#xff09; 单击代码文件&#xff1a;是预览模式&#xff0c;只会显示有限的一两个文件&#xff0c;在一个tab里更新显示 双击代码文件&#xff1a;是编辑模式&#xff0c;可以同时显示多个代码文件…

唯创安全优化纸业车间安全环境:门口盲区预警报警器的应用与成效

一、客户现场 客户主要从事于卷烟纸、成型纸、烟草制造业用纸及其他特定用途纸类制品的加工、生产与销售。在其厂区内&#xff0c;叉车频繁作业&#xff0c;车间环境复杂。经实地查看&#xff0c;发现几大安全隐患&#xff1a; 门口拐角隐患&#xff1a;门口拐角处因卷帘门阻…

Debezium快照事件监听器系统设计

Debezium快照事件监听器系统设计 1. 系统概述 1.1 设计目标 为 Debezium 的快照过程提供可扩展的事件监听机制允许外部系统在快照过程中执行自定义逻辑提供线程安全的事件分发机制确保监听器的异常不会影响主快照流程1.2 核心功能 表快照开始事件监听表快照完成事件监听行数据…

Ubuntu 20.04安装及配置docker

在安装docker的过程中主要参考博客&#xff1a;ubuntu20.04 安装docker (详细版) 但是在测试&#xff1a; sudo docker run hello-world 时报错&#xff1a; docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request ca…

第23天-Python Flet 开发指南

环境准备 pip install flet 示例1:基础计数器应用 import flet as ftdef main(page: ft.Page):page.title = "计数器"page.vertical_alignment = ft.MainAxisAlignment.CENTERtxt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, wid…

牛客网NC21989:牛牛学取余

牛客网NC21989:牛牛学取余 &#x1f4dd; 题目描述 ⏱️ 限制条件 时间限制&#xff1a;C/C/Rust/Pascal 1秒&#xff0c;其他语言2秒空间限制&#xff1a;C/C/Rust/Pascal 32 M&#xff0c;其他语言64 M输入范围&#xff1a;两个整数&#xff0c;在int范围内 &#x1f4e5;…

unity XCharts插件生成曲线图在UICanvas中

【推荐100个unity插件之22】基于UGUI的功能强大的简单易用的Unity数据可视化图表插件——XCharts3.0插件的使用_unity xcharts-CSDN博客