Java多线程梳理

news/2025/10/24 17:14:59/文章来源:https://www.cnblogs.com/18sui/p/19163828

在 Java 中,创建多线程的方式主要有以下几种:


  1. 继承 Thread

通过继承 Thread 类并重写 run() 方法来创建线程。

示例代码:

class MyThread extends Thread {@Overridepublic void run() {System.out.println("线程运行中: " + Thread.currentThread().getName());}
}public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start(); // 启动线程}
}

特点:

  • 简单易用,适合简单的多线程任务。

  • 由于 Java 是单继承,继承 Thread 类后会占用继承名额,不够灵活。


2. 实现 Runnable 接口

通过实现 Runnable 接口并实现 run() 方法来创建线程。

示例代码:

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("线程运行中: " + Thread.currentThread().getName());}
}public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start(); // 启动线程}
}

特点:

  • 更灵活,因为可以实现多个接口,而不受单继承的限制。

  • 适合需要共享资源的场景,因为多个线程可以共享同一个 Runnable 实例。


3. 实现 Callable 接口

通过实现 Callable 接口并实现 call() 方法来创建线程。Callable 可以有返回值,并且可以抛出异常。

示例代码:

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {return "线程运行结果: " + Thread.currentThread().getName();}
}public class Main {public static void main(String[] args) throws Exception {FutureTask<String> futureTask = new FutureTask<>(new MyCallable());Thread thread = new Thread(futureTask);thread.start(); // 启动线程System.out.println(futureTask.get()); // 获取线程返回值}
}

特点:

  • 支持返回值,适合需要获取线程执行结果的场景。

  • 可以抛出异常,方便错误处理。


4. 使用线程池(ExecutorService)

通过线程池管理线程的创建和执行,避免频繁创建和销毁线程的开销。

示例代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Main {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(5); // 创建固定大小的线程池for (int i = 0; i < 10; i++) {executor.execute(() -> {System.out.println("线程运行中: " + Thread.currentThread().getName());});}executor.shutdown(); // 关闭线程池}
}

特点:

  • 高效管理线程资源,适合需要处理大量任务的场景。

  • 支持多种线程池类型(如固定大小、缓存、定时任务等)。


5. 使用 Lambda 表达式(Java 8+)

通过 Lambda 表达式简化 RunnableCallable 的实现。

示例代码:

public class Main {public static void main(String[] args) {// 使用 Lambda 创建 RunnableThread thread = new Thread(() -> {System.out.println("线程运行中: " + Thread.currentThread().getName());});thread.start();}
}

特点:

  • 代码简洁,适合简单的多线程任务。

6. 使用 CompletableFuture(Java 8+)

通过 CompletableFuture 实现异步编程,支持链式调用和组合多个异步任务。

示例代码:

import java.util.concurrent.CompletableFuture;public class Main {public static void main(String[] args) {CompletableFuture.runAsync(() -> {System.out.println("异步任务运行中: " + Thread.currentThread().getName());}).join(); // 等待任务完成}
}

特点:

  • 支持异步编程和任务组合。

  • 适合复杂的多线程场景。


7. 使用 ForkJoinPool(Java 7+)

通过 ForkJoinPool 实现分治任务,适合处理可以拆分的任务。

示例代码:

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;class MyTask extends RecursiveAction {@Overrideprotected void compute() {System.out.println("分治任务运行中: " + Thread.currentThread().getName());}
}public class Main {public static void main(String[] args) {ForkJoinPool pool = new ForkJoinPool();pool.invoke(new MyTask()); // 执行任务}
}

特点:

  • 适合处理可以拆分的任务(如递归任务)。

  • 自动利用多核 CPU 的优势。


总结

Java 中创建多线程的方式主要有以下几种:

  1. 继承 Thread

  2. 实现 Runnable 接口

  3. 实现 Callable 接口

  4. 使用线程池(ExecutorService

  5. 使用 Lambda 表达式

  6. 使用 CompletableFuture

  7. 使用 ForkJoinPool

每种方式都有其适用场景,推荐根据具体需求选择合适的方式。对于现代 Java 开发,线程池和 CompletableFuture 是更推荐的选择,因为它们更高效、更灵活。

线程池是 Java 并发编程中非常重要的工具,它通过复用线程来减少线程创建和销毁的开销,从而提高系统性能。线程池的核心实现类是 ThreadPoolExecutor,其构造函数有七个核心参数,这些参数决定了线程池的行为和特性。


线程池****的七个核心参数

1. corePoolSize(核心线程数

  • 含义:线程池中保持存活的最小线程数,即使这些线程处于空闲状态。

  • 特点

    • 线程池初始化时,默认没有线程,当有任务提交时才会创建线程。

    • 如果设置了 allowCoreThreadTimeOuttrue,核心线程在空闲时也会被回收。

2. maximumPoolSize(最大线程数

  • 含义:线程池中允许存在的最大线程数。

  • 特点

    • 当任务数量超过核心线程数,并且工作队列已满时,线程池会创建新线程,直到线程数达到 maximumPoolSize

    • 如果任务数量继续增加,线程池会触发拒绝策略。

3. keepAliveTime(线程空闲时间)

  • 含义:当线程池中的线程数量超过 corePoolSize 时,空闲线程的存活时间。

  • 特点

    • 如果线程空闲时间超过 keepAliveTime,多余的线程会被回收,直到线程数等于 corePoolSize

    • 如果 allowCoreThreadTimeOuttrue,核心线程也会被回收。

4. unit(时间单位)

  • 含义keepAliveTime 的时间单位。

  • 常用单位

    • TimeUnit.MILLISECONDS(毫秒)

    • TimeUnit.SECONDS(秒)

    • TimeUnit.MINUTES(分钟)

5. workQueue(工作队列)

  • 含义:用于存放待执行任务的阻塞队列。

  • 常用队列类型

    • LinkedBlockingQueue:无界队列(默认),任务数量不受限制,可能导致内存溢出。

    • ArrayBlockingQueue:有界队列,任务数量受队列容量限制。

    • SynchronousQueue:不存储任务的队列,任务直接提交给线程执行。

    • PriorityBlockingQueue:优先级队列,任务按优先级执行。

6. threadFactory(线程工厂)

  • 含义:用于创建新线程的工厂。

  • 特点

    • 可以自定义线程的名称、优先级、是否为守护线程等。

    • 默认使用 Executors.defaultThreadFactory()

7. handler(拒绝策略)

  • 含义:当线程池无法处理新任务时的拒绝策略。

  • 常用策略

    • AbortPolicy(默认):直接抛出 RejectedExecutionException 异常。

    • CallerRunsPolicy:由提交任务的线程直接执行该任务。

    • DiscardPolicy:直接丢弃任务,不抛出异常。

    • DiscardOldestPolicy:丢弃队列中最旧的任务,然后重新提交当前任务。


线程池****的工作流程

  1. 当提交一个新任务时:

    1. 如果当前线程数 < corePoolSize,创建新线程执行任务。

    2. 如果当前线程数 >= corePoolSize,将任务放入工作队列。

    3. 如果工作队列已满且当前线程数 < maximumPoolSize,创建新线程执行任务。

    4. 如果工作队列已满且当前线程数 >= maximumPoolSize,触发拒绝策略。

  2. 当线程空闲时间超过 keepAliveTime 时:

    1. 如果当前线程数 > corePoolSize,回收多余线程。

    2. 如果 allowCoreThreadTimeOuttrue,核心线程也会被回收。


示例代码

import java.util.concurrent.*;public class ThreadPoolExample {public static void main(String[] args) {// 创建线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(2, // corePoolSize5, // maximumPoolSize60, // keepAliveTimeTimeUnit.SECONDS, // unitnew LinkedBlockingQueue<>(10), // workQueueExecutors.defaultThreadFactory(), // threadFactorynew ThreadPoolExecutor.AbortPolicy() // handler);// 提交任务for (int i = 0; i < 15; i++) {int taskId = i;executor.execute(() -> {System.out.println("任务 " + taskId + " 正在执行,线程: " + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}// 关闭线程池executor.shutdown();}
}

总结

线程池的七个核心参数决定了线程池的行为和性能:

  1. corePoolSize:核心线程数。

  2. maximumPoolSize:最大线程数。

  3. keepAliveTime:线程空闲时间。

  4. unit:时间单位。

  5. workQueue:工作队列。

  6. threadFactory:线程工厂。

  7. handler:拒绝策略。

合理配置这些参数可以优化线程池的性能,避免资源浪费和任务丢失。

在 Java 中,线程的状态是通过 Thread.State 枚举类来表示的。线程在其生命周期中会经历不同的状态,这些状态反映了线程当前的活动情况。以下是 Java 中线程的六种状态:


1. NEW(新建)

  • 描述:线程被创建但尚未启动。

  • 触发条件

    • 调用 new Thread() 创建线程对象,但尚未调用 start() 方法。
  • 示例

    Thread thread = new Thread(() -> {});
    System.out.println(thread.getState()); // 输出: NEW
    

2. RUNNABLE (可运行)

  • 描述:线程正在 JVM 中执行,但可能正在等待操作系统资源(如 CPU)。

  • 触发条件

    • 调用 start() 方法后,线程进入 RUNNABLE 状态。

    • 线程可能正在运行,也可能在等待 CPU 时间片。

  • 示例

    Thread thread = new Thread(() -> {while (true) {}
    });
    thread.start();
    System.out.println(thread.getState()); // 输出: RUNNABLE
    

3. BLOCKED(阻塞)

  • 描述:线程被阻塞,等待获取监视器锁(monitor lock)。

  • 触发条件

    • 线程试图进入一个被其他线程持有的 synchronized 代码块或方法。
  • 示例

    Object lock = new Object();Thread thread1 = new Thread(() -> {synchronized (lock) {while (true) {}}
    });Thread thread2 = new Thread(() -> {synchronized (lock) {System.out.println("Thread 2 获取锁");}
    });thread1.start();
    Thread.sleep(100); // 确保 thread1 先获取锁
    thread2.start();
    Thread.sleep(100); // 确保 thread2 进入 BLOCKED 状态
    System.out.println(thread2.getState()); // 输出: BLOCKED
    

4. WAITING(等待)

  • 描述:线程无限期等待,直到被其他线程显式唤醒。

  • 触发条件

    • 调用 Object.wait()Thread.join()LockSupport.park() 方法。
  • 示例

    Thread thread = new Thread(() -> {synchronized (Thread.currentThread()) {try {Thread.currentThread().wait(); // 进入 WAITING 状态} catch (InterruptedException e) {e.printStackTrace();}}
    });thread.start();
    Thread.sleep(100); // 确保线程进入 WAITING 状态
    System.out.println(thread.getState()); // 输出: WAITING
    

5. TIMED_WAITING(超时等待)

  • 描述:线程在指定的时间内等待,超时后自动唤醒。

  • 触发条件

    • 调用 Thread.sleep(long)Object.wait(long)Thread.join(long)LockSupport.parkNanos() 等方法。
  • 示例

    Thread thread = new Thread(() -> {try {Thread.sleep(1000); // 进入 TIMED_WAITING 状态} catch (InterruptedException e) {e.printStackTrace();}
    });thread.start();
    Thread.sleep(100); // 确保线程进入 TIMED_WAITING 状态
    System.out.println(thread.getState()); // 输出: TIMED_WAITING
    

6. TERMINATED (终止)

  • 描述:线程已经执行完毕,或者因异常退出。

  • 触发条件

    • 线程的 run() 方法执行完毕。

    • 线程因未捕获的异常而终止。

  • 示例

    Thread thread = new Thread(() -> {System.out.println("线程执行完毕");
    });thread.start();
    thread.join(); // 等待线程执行完毕
    System.out.println(thread.getState()); // 输出: TERMINATED
    

线程状态转换图

以下是线程状态的典型转换关系:

NEW → RUNNABLE → BLOCKED → RUNNABLE → TERMINATED↓        ↓WAITING → RUNNABLE↓TIMED_WAITING → RUNNABLE

总结

Java 线程的六种状态和特点:

  1. NEW:线程被创建但未启动。

  2. RUNNABLE:线程正在运行或等待 CPU 资源。

  3. BLOCKED:线程等待获取锁。

  4. WAITING:线程无限期等待。

  5. TIMED_WAITING:线程在指定时间内等待。

  6. TERMINATED:线程执行完毕或异常终止。

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

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

相关文章

QT的事件循环(一)

目录浅议Qt的事件处理机制 一浅议Qt的事件处理机制 二 转载自CSDN系列文章, 原文链接:https://blog.csdn.net/changsheng230/article/details/6085080 浅议Qt的事件处理机制 一 深入了解事件处理系统对于每个学习Qt人…

深入解析:数据结构 之 【图的遍历与最小生成树】(广度优先遍历算法、深度优先遍历算法、Kruskal算法、Prim算法实现)

深入解析:数据结构 之 【图的遍历与最小生成树】(广度优先遍历算法、深度优先遍历算法、Kruskal算法、Prim算法实现)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important…

完整教程:构建并运行最小 Linux 内核

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

word批量转pdf

方法:使用Microsoft Word批处理宏 批量实现Word转PDF功能,适合办公人员。无需安装额外软件,操作简单,原生支持。 (1)打开任意 Word 文档,按下 Alt + F11 打开 VBA 编辑器(点击“开发工具”,点击“visual Basi…

【SAE出版 | 高届数 | 检索稳定】第七届土木建筑与城市工程国际学术会议(ICCAUE 2025)

第七届土木建筑与城市工程国际学术会议(ICCAUE 2025)将于2025年10月31日-11月2日在中国贵阳召开。【天津大学、中交天津港湾工程研究院有限公司主办!】 【高届数土木会议 | SAE出版,检索稳定!】 第七届土木建筑与…

qcefview库的使用

目录背景运行环境qcefview源码阅读代码目录代码结构列举的通讯方式通讯方式一,widget中的函数通知web页面改变通讯方式二、鼠标拖拽事件通讯方式三、c++中invoke函数响应(两种UrlRequest、QueryRequest)QCefView中定…

解决Qt 不能debug问题

排查思路 1. 工程配置 通过deepseek查询得到编译选项需要+g,如下 CONFIG += debug QMAKE_CXXFLAGS += -g QMAKE_LFLAGS += -g 1.1. 排查系统的gdb文件是哪个,看是不是期望和和编译配置应用的编译器配套 ----如,都使…

2025年项目总延期?这30款项目进度管理软件让我提前交付率85%!

项目总延期是困扰团队效率的常见难题,但选对工具能让交付率提升至85%以上。本文将为您精选30款高效的项目进度管理软件,覆盖从敏捷开发到传统瀑布模型的不同需求。无论是禅道的全流程管控、Jira的敏捷适配性,还是Tr…

2025 年最新护眼灯生产厂家推荐榜:含全光谱智能照明标杆企业及高产能品牌优选指南自然光护眼/全光谱护眼/儿童护眼吸顶灯公司推荐

引言 当下,电子设备普及让人们日均用眼时长远超以往,护眼照明需求急剧攀升,但护眼灯市场乱象却让消费者陷入困境。众多产品仅靠 “护眼” 噱头吸引购买,实际在光谱连续性、防蓝光效果、频闪控制等核心指标上未达健…

Exadata数据库性能异常,备份进程卡住

1、案例概述 某客户有一台Exadata X9M-2,据客户反馈:“晚上20:30分,开始expdp备份,20:32分卡住。同时,在20:30分也发起了RMAN备份,RMAN备份在21:44也卡住。之后,杀掉进程,并重启恢复正常。” 现在,客户希望分…

做本地门户网站 10 年,我靠微擎摆脱了 “客户需求五花八门” 的噩梦

在我们这座三线城市,我经营的 “小城网” 算小有名气 —— 做了 10 年本地门户网站,从最初帮商家挂广告,到后来承接小程序、公众号开发,手里攒了 200 多个本地客户。可这两年,我却越来越怕接客户的电话,不是不想…

2025 年国内吸顶灯源头厂家最新推荐排行榜:聚焦全光谱技术与品质生产,精选优质厂家助力家居照明选购全光谱/中山现代/客厅现代/吊灯吸顶灯公司推荐

引言 当前家居照明市场中,吸顶灯因适配场景广、照明效果稳定成为众多家庭首选,但市场乱象却给消费者选购带来极大困扰。一方面,品牌数量繁杂且质量差距悬殊,部分小厂家使用劣质材料生产,导致产品存在寿命短、光效…

RabbitMQ框架及应用场景

简介 RabbitMQ是一个使用Erlang,基于AMQP协议的MQ组件。 AMQP全称为 Advanced Message Queuing Protocol(高级消息队列协议****),是一个面向消息的中间件传输协议,用于在应用程序之间进行异步消息通信。 AMQP协议…

UNIX下C语言编程与实践11-UNIX 动态库显式调用:dlopen、dlsym、dlerror、dlclose 函数的使用与实例 - 指南

UNIX下C语言编程与实践11-UNIX 动态库显式调用:dlopen、dlsym、dlerror、dlclose 函数的使用与实例 - 指南2025-10-24 16:56 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: …

熟知大模型中mcp概念 --by zk

MCP核心概念解析 什么是MCP:让大模型拥有“手和脚” 大模型本身只有对话和决策能力,没有执行调用工具,获取资源的能力。因此定义一套让大模型调用外部能力的通用协议很重要。MCP(Model Context Protocol)是一套让…

【开题答辩全过程】以 “辛巴克餐饮”小程序为例,具备答辩的问题和答案

【开题答辩全过程】以 “辛巴克餐饮”小程序为例,具备答辩的问题和答案pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: …

2025年一体化雨水提升泵站厂家权威推荐榜单:污水提升泵站/一体化污水泵站/一体化雨水泵站源头厂家精选

在市政排水与水资源管理领域,一体化雨水提升泵站已成为现代城市基础设施的核心组成部分,其高效性能直接关系到城市防洪排涝能力与水环境保护质量。 随着全球城市化进程加速,市政排水系统面临前所未有的压力。据最新…

STM32软件I2C读写AT24C64 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

bcc

bcc原理从内核中获取数据。 整个工具的核心原理是利用 eBPF 技术,在内核中与块设备 I/O 相关的关键函数上设置探针(Tracepoint),从而在几乎无开销的情况下捕获 I/O 请求的开始和结束时间,计算出延迟,并将结果存入…

手写ibatis

通用 Mapper:提供通用的 CRUD 方法。条件构造器:支持链式调用,构建查询条件。分页查询:支持 Oracle 的分页查询。连表查询:支持 JOIN 查询。指定字段查询:支持动态选择查询字段。注解支持:通过注解配置实体类和…