线程池 | java中的多线程

devtools/2025/1/23 4:49:43/

在 《Java异步编程 | CompletableFuture--实现复杂的异步控制流
》中,我们提到了 通过 自定义线程池 , 用于管理 异步任务的执行,避免频繁创建和销毁线程,提高性能。

本文将整理并介绍一些 Java 中常见的 多线程创建方式,用于 更好地理解和选择 合适的线程管理策略

本文整理了下述5种 创建多线程 的方式

  1. 实现 Runnable 接口
  2. 继承 Thread 类
  3. 使用 Callable 和 FutureTask
  4. 使用线程池(ExecutorService)
  5. CompletableFuture

一、实现 Runnable 接口

  • 方式:通过 实现 Runnable 接口的 run() 方法 ,定义线程要执行的任务,然后将 Runnable 对象 传入 Thread 构造函数,最后调用 start() 方法启动线程。
  • 优点:可以避免继承 Thread 类的限制,Runnable 可以被 多个线程共享
  • 代码示例
java">class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Thread is running");}
}public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();}
}

二、继承 Thread

  • 方式:直接 继承 Thread 类,并重写 run() 方法,创建 子类对象 并调用 start() 方法启动线程。
  • 优点:简单直观,适用于线程功能比较单一的情况。
  • 缺点:Java 不支持多重继承,因此如果已经继承了其他类,就不能再继承 Thread 类。
  • 代码示例
java">class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread is running");}
}public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
}

三、使用 CallableFutureTask

  • 方式Callable 接口与 Runnable 类似,但它可以 返回结果抛出异常。通过 FutureTask 来包装 Callable 对象,再通过 Thread 启动。
  • 优点:可以获取任务的 执行结果,并处理异常。
  • 代码示例
java">class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {return 100;}
}public class Main {public static void main(String[] args) throws Exception {FutureTask<Integer> task = new FutureTask<>(new MyCallable());Thread thread = new Thread(task);thread.start();Integer result = task.get(); // 获取任务执行结果System.out.println("Result: " + result);}
}

四、使用线程池(ExecutorService

  • 方式:线程池通过 ExecutorService 提供一个更高层的 API,管理线程的 创建、调度和销毁。可以使用线程池来提交 RunnableCallable 任务,避免手动管理线程,特别适合 处理大量并发任务
  • 优点:线程池能够重用线程,避免线程的频繁创建和销毁,提高了效率;还可以 控制并发线程的数量
  • 代码示例
java">class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Thread is running in a thread pool");}
}public class Main {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(10); // 创建一个大小为10的线程池executor.submit(new MyRunnable()); // 提交任务executor.shutdown(); // 关闭线程池}
}

(一) 核心方法

  • submit(Runnable task):提交一个没有返回值的任务。
  • submit(Callable<T> task):提交一个有返回值的任务,返回一个 Future<T> 对象,可以通过 get() 方法获取任务的执行结果。
  • invokeAll(Collection<? extends Callable<T>> tasks):提交一组任务并等待所有任务完成,返回每个任务的结果。
  • invokeAny(Collection<? extends Callable<T>> tasks):提交一组任务,返回最先完成的任务的结果。
  • shutdown():启动优雅关闭,停止接收新的任务,并等待现有任务完成。
  • shutdownNow():立即关闭线程池,尝试中断所有正在执行的任务并返回待执行的任务列表。

(二) ExecutorService 的实现类

Java 提供了几种常用的线程池实现类:

1. newFixedThreadPool(int nThreads)
  • 创建一个固定大小的线程池,线程池中始终有固定数量的线程。适合于处理需要固定线程数的任务。
  • 如果线程池中有线程空闲,新的任务将由空闲线程执行;如果线程池已满,新任务将被放入任务队列等待。

示例

java">ExecutorService executor = Executors.newFixedThreadPool(3);
2. newCachedThreadPool()
  • 创建一个可以根据需要创建新线程的线程池,如果线程池中的线程空闲超过60秒就会被回收。适合于执行大量短时间的异步任务。
  • 线程池的大小根据系统需求动态调整。

示例

java">ExecutorService executor = Executors.newCachedThreadPool();
3. newSingleThreadExecutor()
  • 创建一个只有一个线程的线程池,所有提交的任务将顺序执行。适合于需要按顺序执行任务的场景。

示例

java">ExecutorService executor = Executors.newSingleThreadExecutor();
4. newScheduledThreadPool(int corePoolSize)
  • 创建一个固定大小的线程池,适用于定时任务和周期性任务的执行。

示例

java">ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
executor.schedule(() -> {System.out.println("Scheduled task executed");
}, 1, TimeUnit.SECONDS);

(三) ExecutorService 的作用

  1. 管理线程池ExecutorService 负责创建和管理一个或多个线程池,它从池中获取线程来执行任务。与直接创建线程(如通过 new Thread())相比,使用线程池更加高效和灵活,特别是在处理大量短小任务时,线程池能有效避免线程频繁创建和销毁的开销。
  2. 任务提交: 它通过 submit() 方法将任务提交给线程池执行,返回一个 Future 对象,Future 允许我们获取任务的执行结果或取消任务。
  3. 任务调度ExecutorService 提供了强大的任务调度功能,可以安排任务在未来某个时刻执行,或者定期执行任务。例如,使用 schedule() 方法,任务可以按照固定的延迟执行或以固定的周期重复执行。
  4. 线程复用: 线程池内部维护了一组线程,线程池中的线程可以被复用,执行完一个任务后,线程会返回池中准备执行下一个任务。这样避免了每次执行任务都需要创建和销毁线程的性能消耗。
  5. 优雅关闭ExecutorService 提供了 shutdown() 方法来优雅地关闭线程池,这样线程池中的线程会完成正在执行的任务并终止,新的任务将不会被接受。它还提供了 shutdownNow() 方法,用于立即关闭线程池并尝试停止所有正在执行的任务。

五、CompletableFuture(本质也是线程池)

有关CompletableFuture,详见 《Java异步编程 | CompletableFuture–实现复杂的异步控制流》

  • 方式CompletableFuture 是 Java 8 引入的 API,用于处理异步编程。它可以非常方便地处理异步任务之间的依赖关系,并支持链式调用。它默认使用 ForkJoinPool 来执行任务,提供了比 Future 更强大的功能。
  • 优点:支持异步编程,并能链式调用,简化了异步任务的处理。
  • 代码示例
java">CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {System.out.println("Asynchronous task");
});future.thenRun(() -> {System.out.println("Another task after first one");
});

http://www.ppmy.cn/devtools/152782.html

相关文章

opencv projectPoints函数 computeCorrespondEpilines函数 undistortPoints函数

opencv projectPoints函数 cv::projectPoints 是 OpenCV 中用于将三维点投影到二维图像平面的函数。它通常用于计算在相机坐标系下的三维点在图像坐标系中的位置&#xff0c;考虑了相机的内参和外参。 函数原型 void cv::projectPoints(InputArray objectPoints,InputArray …

20250120面试鸭特训营第28天

更多特训营笔记详见个人主页【面试鸭特训营】专栏 250120 1. 说说 Java 中 HashMap 的原理&#xff1f; HashMap 的底层结构 HashMap 底层由 node 数组、单链表、红黑树构成。根据哈希函数计算得到哈希值&#xff0c;哈希值确定了元素保存在 node 数组中的具体下标。HashMap…

【16届蓝桥杯寒假刷题营】第1期DAY5

问题描述 小蓝非常热爱数学&#xff0c;一天老师给小蓝出了一道数学题&#xff0c;想锻炼锻炼小蓝的思维能力。题目是这样的&#xff1a;给定两个数 a 和 b&#xff0c;在 a 到 b&#xff08;包括 a 和 b&#xff09;之间所有数的平方当中&#xff0c;试问有几个数能够表示为 …

Oracle事务(7)

7. 事务 7.1. 事务概念 事务(Transaction)是不可分割的一系列数据库操作,这些操作必须要么整体成功,要么整体失败。事务维护数据完整性,保证数据库总是在一个一致性状态。事务应该以commit或rollback语句结束。如果它以commit语句结束,所有对数据库的改变被永久记录。如…

62,【2】 BUUCTF WEB [强网杯 2019]Upload1

进入靶场 此处考点不是SQL&#xff0c;就正常注册并登录进去 先随便传一个 进行目录扫描&#xff0c;我先用爆破代替 先随便后面写个文件名 为了提供payload位置 www.tar.gz真的存在 返回浏览器修改url就自动下载了 看到tp5,应该是ThinkPHP5框架 参考此博客的思路方法c[强网杯…

Visual Studio Community 2022(VS2022)安装方法

废话不多说直接上图&#xff1a; 直接上步骤&#xff1a; 1&#xff0c;首先可以下载安装一个Visual Studio安装器&#xff0c;叫做Visual Studio installer。这个安装文件很小&#xff0c;很快就安装完成了。 2&#xff0c;打开Visual Studio installer 小软件 3&#xff0c…

SpringBoot集成Flink-CDC,实现对数据库数据的监听

一、什么是 CDC &#xff1f; CDC 是Change Data Capture&#xff08;变更数据获取&#xff09;的简称。 核心思想是&#xff0c;监测并捕获数据库的变动&#xff08;包括数据或数据表的插入、 更新以及删除等&#xff09;&#xff0c;将这些变更按发生的顺序完整记录下来&…

Jenkins-git配置说明!

git是流行的分布式控制系统。在jenkins中有许多插件提供了对git的支持。 在java环境中的发布构建工作。 通常情况下&#xff0c;会有源码管理(source code management)项,一般只要写入git仓库的url和认证机制即可。然而&#xff0c;总会有一些比较复杂的环境&#xff0c;会使用…