当前位置: 首页 > news >正文

Java多线程梳理

在 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.zskr.cn/news/29552.html

相关文章:

  • 【SAE出版 | 高届数 | 检索稳定】第七届土木建筑与城市工程国际学术会议(ICCAUE 2025)
  • 2025 年最新护眼灯生产厂家推荐榜:含全光谱智能照明标杆企业及高产能品牌优选指南自然光护眼/全光谱护眼/儿童护眼吸顶灯公司推荐
  • 2025 年国内吸顶灯源头厂家最新推荐排行榜:聚焦全光谱技术与品质生产,精选优质厂家助力家居照明选购全光谱/中山现代/客厅现代/吊灯吸顶灯公司推荐
  • RabbitMQ框架及应用场景
  • UNIX下C语言编程与实践11-UNIX 动态库显式调用:dlopen、dlsym、dlerror、dlclose 函数的使用与实例 - 指南
  • 手写ibatis
  • 国产IPD项目管理软件推荐|别再靠 Excel 推 IPD 了!帮你把IPD流程从“纸上”搬进系统
  • 【源码解读之 Mybatis】【核心篇】--第7篇:ParameterHandler参数处理机制
  • [linux] 文件夹可写权限的关闭和打开
  • 备份恢复:backup database format plus archivelog归档备份集路径与数据库format指定不一致
  • 从“天书”到源码:HarmonyOS NEXT 崩溃堆栈解析实战指南
  • 2025年江苏博士后微服务公司权威推荐榜单:博士后服务团/高层次人才服务/高层次人才引进源头公司精选
  • Launcher 桌面源码笔记一(3D车模桌面)
  • Microsoft Visual C++ 运行库安装教程(最新版完整指南|DLL缺失修复方案)
  • 2025 年硫酸钡板生产厂家最新推荐排行榜:结合协会测评权威数据,揭晓实力企业高纯度/ct 室/牙科/辐射硫酸钡板公司推荐
  • 2025 年最新推荐!软件验收测试公司最新排行榜,揭秘具备 CMA/CNAS 资质的靠谱品牌可靠/权威/知名的软件验收测试公司推荐
  • ABP vNext 基础四层
  • 在线聊天室
  • 2025 年亚克力大型鱼缸厂家联系方式推荐:江苏金穗的全产业链服务与定制化技术优势解析
  • 2025 年亚克力板材厂家联系方式推荐:江苏金穗技术工艺与工程案例解析,泳池 / 鱼缸 / 海洋馆解决方案
  • 2025山东单招综评培训机构推荐榜:济南易升教育五星领跑,小班培养 + 高上岸率适配升学需求
  • 实用指南:npm 包构建与发布
  • 2025 全案/VI/品牌设计公司服务商推荐:意识形体(上海意感)五星领跑,这些专注视觉价值的公司值得选
  • 一网统管,智慧赋能:国标GB28181算法算力平台EasyGBS构建城市交通可视、巡检与指挥新范式
  • oracle 控制文件
  • 完整教程:数据类型和变量1
  • 2025年苏州中式秀禾服婚纱照公司权威推荐榜单:海边婚纱照/园林婚纱照/旅拍婚纱照源头公司精选
  • mssqsl靶机的sa权限sql注入-cnblog
  • 国产9GHz宽带巴伦HT-BAL-0009SMG实测反馈——pin-to-pin替代海外料,EVM直接降4个点
  • Java使用Selenium自动化测试网盘链接是否失效