线程池与并发工具:让并发编程更简单、高效!
全文目录:
- 开篇语
- 前言
- 一、Executor框架与线程池
- 1.1 Executor 框架概述
- 1.2 创建线程池
- 代码示例:使用 `ExecutorService` 创建线程池
- 二、Callable 与 Future 接口
- 2.1 `Callable` 接口
- 2.2 `Future` 接口
- 代码示例:使用 `Callable` 和 `Future`
- 三、CountDownLatch、CyclicBarrier 等同步工具类
- 3.1 `CountDownLatch`
- 代码示例:使用 `CountDownLatch`
- 3.2 `CyclicBarrier`
- 代码示例:使用 `CyclicBarrier`
- 四、ForkJoin框架与并行计算
- 4.1 `ForkJoin` 框架的基本概念
- 代码示例:使用 `ForkJoinPool`
- 总结:高效并发与线程控制
- 文末
开篇语
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛
今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。
我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
前言
在多线程编程中,线程的创建和销毁是非常耗费资源的,频繁地创建和销毁线程会导致性能下降。为了提高并发性能,Java 提供了线程池和其他并发工具类,这些工具能够帮助我们更高效地管理和执行线程,减少资源的浪费。今天我们将深入探讨 Executor框架与线程池、Callable与Future接口、CountDownLatch、CyclicBarrier等同步工具类,以及 ForkJoin框架与并行计算。
一、Executor框架与线程池
Java 提供了 Executor
框架,用于管理和控制线程池。线程池能够复用线程,避免了每次任务提交时都要创建新线程的开销,从而提升了程序的性能。
1.1 Executor 框架概述
Executor
是一个接口,定义了用于执行异步任务的方法。ExecutorService
是 Executor
的子接口,它定义了更丰富的线程池管理和任务控制功能。
常见的线程池实现类包括:
- ThreadPoolExecutor:最常用的线程池实现,能够自定义线程池的各项参数。
- ScheduledThreadPoolExecutor:支持定时任务的线程池。
- Executors:提供了静态方法来快速创建各种线程池。
1.2 创建线程池
通过 Executors
类的静态工厂方法,可以创建不同类型的线程池。常见的线程池类型包括:
newFixedThreadPool(int nThreads)
:创建一个固定大小的线程池。newCachedThreadPool()
:创建一个可以根据需要创建新线程的线程池,空闲线程会被回收。newSingleThreadExecutor()
:创建一个单线程线程池。
代码示例:使用 ExecutorService
创建线程池
import java.util.concurrent.*;public class ExecutorExample {public static void main(String[] args) {// 创建一个固定大小的线程池ExecutorService executorService = Executors.newFixedThreadPool(3);// 提交任务给线程池executorService.submit(() -> {System.out.println("任务正在执行,线程名:" + Thread.currentThread().getName());});// 关闭线程池executorService.shutdown();}
}
在这个例子中,我们创建了一个固定大小的线程池 executorService
,并提交了一个任务。线程池管理着任务的执行和线程的复用,避免了频繁创建和销毁线程的开销。
二、Callable 与 Future 接口
在使用线程池执行任务时,Runnable
只能返回 void
,它不允许任务执行的结果返回给调用者。如果我们希望任务有返回值,或者需要捕获异常,可以使用 Callable
接口和 Future
接口。
2.1 Callable
接口
Callable
与 Runnable
类似,都是用于表示任务,但不同之处在于 Callable
允许任务执行有返回值,并且可以抛出异常。call()
方法返回任务的结果。
2.2 Future
接口
Future
是用于表示异步计算结果的接口。通过 Future
对象,我们可以检查任务是否完成,取消任务,或者获取任务的结果。
代码示例:使用 Callable
和 Future
import java.util.concurrent.*;public class CallableFutureExample {public static void main(String[] args) throws InterruptedException, ExecutionException {ExecutorService executorService = Executors.newFixedThreadPool(2);// 创建一个 Callable 任务Callable<Integer> task = () -> {System.out.println("任务开始,线程名:" + Thread.currentThread().getName());Thread.sleep(2000); // 模拟任务执行return 123; // 返回结果};// 提交任务并获取 Future 对象Future<Integer> future = executorService.submit(task);// 获取任务结果Integer result = future.get(); // 阻塞,直到任务完成并返回结果System.out.println("任务执行结果:" + result);executorService.shutdown();}
}
在这个例子中,我们创建了一个 Callable
任务,并通过 submit()
方法将其提交给线程池。future.get()
方法会阻塞并等待任务执行完毕,最终返回结果。
三、CountDownLatch、CyclicBarrier 等同步工具类
Java 提供了多种同步工具类,用于协调多线程之间的执行顺序。常见的同步工具类包括 CountDownLatch
和 CyclicBarrier
。
3.1 CountDownLatch
CountDownLatch
用于使一个或多个线程等待直到在其他线程中执行的一组操作完成。在某些情况下,多个线程必须等待某些任务完成后才能继续执行。
await()
:让当前线程等待。countDown()
:减少计数器的值,当计数器为零时,所有等待线程会被释放。
代码示例:使用 CountDownLatch
import java.util.concurrent.*;public class CountDownLatchExample {public static void main(String[] args) throws InterruptedException {int taskCount = 3;CountDownLatch latch = new CountDownLatch(taskCount);// 启动多个线程for (int i = 0; i < taskCount; i++) {int taskId = i + 1;new Thread(() -> {try {System.out.println("任务 " + taskId + " 正在执行...");Thread.sleep(1000); // 模拟任务执行latch.countDown(); // 任务完成,计数器减1} catch (InterruptedException e) {e.printStackTrace();}}).start();}latch.await(); // 等待所有任务完成System.out.println("所有任务完成,继续执行主线程");}
}
在这个例子中,主线程通过 latch.await()
等待所有子线程执行完成。每个子线程完成任务后通过 latch.countDown()
减少计数器,直到所有子线程完成,主线程才继续执行。
3.2 CyclicBarrier
CyclicBarrier
用于让一组线程在某个公共屏障点上等待,直到所有线程都到达屏障点为止。与 CountDownLatch
不同的是,CyclicBarrier
在多次使用时会被重置。
代码示例:使用 CyclicBarrier
import java.util.concurrent.*;public class CyclicBarrierExample {public static void main(String[] args) throws InterruptedException {int parties = 3;CyclicBarrier barrier = new CyclicBarrier(parties, () -> System.out.println("所有线程到达屏障点,继续执行"));// 启动多个线程for (int i = 0; i < parties; i++) {int threadId = i + 1;new Thread(() -> {try {System.out.println("线程 " + threadId + " 到达屏障点");barrier.await(); // 等待其他线程到达屏障点} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}).start();}}
}
在这个例子中,CyclicBarrier
的每个线程都会等待其他线程到达屏障点,直到所有线程都到达,屏障才会被释放,允许所有线程继续执行。
四、ForkJoin框架与并行计算
ForkJoin
框架是 Java 7 引入的一个新框架,专门用于并行任务的分解和执行。它适用于需要分解为多个子任务的任务,像是大数据计算、图像处理、并行算法等。
4.1 ForkJoin
框架的基本概念
- Fork:将任务分解为多个子任务。
- Join:等待所有子任务完成,并将结果合并。
ForkJoinPool
是 ForkJoin
框架的核心类,用于执行和管理分解后的任务。
代码示例:使用 ForkJoinPool
import java.util.concurrent.*;public class ForkJoinExample {public static void main(String[] args) throws InterruptedException, ExecutionException {ForkJoinPool forkJoinPool = new ForkJoinPool();// 定义一个递归任务RecursiveTask<Integer> task = new RecursiveTask<>() {@Overrideprotected Integer compute() {return 1 + 2; // 简单示例:返回 1 + 2}};// 提交任务并获取结果Future<Integer> result = forkJoinPool.submit(task);System.out.println("任务结果:" + result.get()); // 输出任务执行结果}
}
在这个例子中,我们使用 ForkJoinPool
提交了一个递归任务,它返回了 1 + 2 的结果。ForkJoin
框架特别适合用来处理需要并行计算的任务。
总结:高效并发与线程控制
通过使用线程池、同步工具类和 ForkJoin
框架,Java 为我们提供了强大的并发编程支持。Executor
框架帮助我们管理线程池,Callable
和 Future
接口使得任务可以有返回值,CountDownLatch
和 CyclicBarrier
用于协调线程之间的同步,而 ForkJoin
框架则能高效地进行并行计算。
掌握这些并发工具,你就能在多线程编程中更加游刃有余,构建出高效、可扩展的并发应用!
… …
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
… …
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。
版权声明:本文由作者原创,转载请注明出处,谢谢支持!