当前位置: 首页 > 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.hskmm.com/?act=detail&tid=38229

相关文章:

  • QT的事件循环(一)
  • 【开题答辩全过程】以 “辛巴克餐饮”小程序为例,具备答辩的问题和答案
  • QT中的反射机制
  • Exadata数据库性能异常,备份进程卡住
  • [linux] 文件夹可写权限的关闭和打开
  • 熟知大模型中mcp概念 --by zk
  • 2025年一体化雨水提升泵站厂家权威推荐榜单:污水提升泵站/一体化污水泵站/一体化雨水泵站源头厂家精选
  • 【源码解读之 Mybatis】【核心篇】--第7篇:ParameterHandler参数处理机制
  • 2025年教室护眼灯厂家权威推荐榜单:led教室灯/幼儿园教室灯/教室照明灯具源头厂家精选
  • 2025年自动定量灌装机厂家权威推荐榜单:称重灌装机/膏状灌装机/瓶灌装机源头厂家精选
  • 厨房电子秤芯片方案:SIC8833
  • 备份恢复:backup database format plus archivelog归档备份集路径与数据库format指定不一致
  • 在MCUXpresso IDE中建立使用静态库的工程 - 指南
  • 从“天书”到源码:HarmonyOS NEXT 崩溃堆栈解析实战指南
  • 深入理解Java线程
  • 2025年江苏博士后微服务公司权威推荐榜单:博士后服务团/高层次人才服务/高层次人才引进源头公司精选
  • RFSOC学习记录(六)混频模式分析
  • OSI七层网络参考模型(Leo)
  • 2025 年最新推荐河道护栏源头厂家口碑榜,聚焦全流程服务与高性价比之选铝合金/绳索/不锈钢河道护栏公司推荐
  • ABP vNext 基础四层
  • 2025 年管道修补器源头厂家最新推荐排行榜:揭秘行业内具备全流程管控能力的靠谱厂商及优质产品选型指南加长/铸铁/弯头/卡箍式管道修补器公司推荐
  • 2025 年最新推荐!软件验收测试公司最新排行榜,揭秘具备 CMA/CNAS 资质的靠谱品牌可靠/权威/知名的软件验收测试公司推荐
  • Socket 编程 TCP(准备阶段) - 指南
  • 信号(Signal)、信号量(Semaphore)
  • 在线聊天室
  • 2025 年亚克力板材厂家联系方式推荐:江苏金穗技术工艺与工程案例解析,泳池 / 鱼缸 / 海洋馆解决方案
  • 2025 年 亚克力透明泳池厂家联系方式推荐:江苏金穗的技术积淀与工程服务优势解析
  • vue3+vite学习日记之配置全新项目
  • 2025 全案/VI/品牌设计公司服务商推荐:意识形体(上海意感)五星领跑,这些专注视觉价值的公司值得选
  • 2025 年水泥房厂家联系方式推荐,内蒙古蒙营新型建材提供预制水泥房及配套产品专业解决方案