多线程与高并发-JDK1.8线程池创建的几种方式-《Java笔记》

admin 2025-10-19 02:14:23 编程 来源:ZONE.CI 全球网 0 阅读模式

Java 线程池

线程池创建的几种方式

newFixedThreadPool

定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程测试代码:

  1. public class TestThreadPool {
  2. //定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程
  3. static ExecutorService fixedExecutor = Executors.newFixedThreadPool(3);
  4. public static void main(String[] args) {
  5. testFixedExecutor();
  6. }
  7. //测试定长线程池,线程池的容量为3,提交6个任务,根据打印结果可以看出先执行前3个任务,3个任务结束后再执行后面的任务
  8. private static void testFixedExecutor() {
  9. for (int i = 0; i < 6; i++) {
  10. final int index = i;
  11. fixedExecutor.execute(new Runnable() {
  12. public void run() {
  13. try {
  14. Thread.sleep(3000);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. System.out.println(Thread.currentThread().getName() + " index:" + index);
  19. }
  20. });
  21. }
  22. try {
  23. Thread.sleep(4000);
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. }
  27. System.out.println("4秒后...");
  28. fixedExecutor.shutdown();
  29. }
  30. }

打印结果:

  1. pool-1-thread-1 index:0
  2. pool-1-thread-2 index:1
  3. pool-1-thread-3 index:2
  4. 4秒后...
  5. pool-1-thread-3 index:5
  6. pool-1-thread-1 index:3
  7. pool-1-thread-2 index:4

newCachedThreadPool

可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制测试代码:

  1. public class TestThreadPool {
  2. //可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制
  3. static ExecutorService cachedExecutor = Executors.newCachedThreadPool();
  4. public static void main(String[] args) {
  5. testCachedExecutor();
  6. }
  7. //测试可缓存线程池
  8. private static void testCachedExecutor() {
  9. for (int i = 0; i < 6; i++) {
  10. final int index = i;
  11. cachedExecutor.execute(new Runnable() {
  12. public void run() {
  13. try {
  14. Thread.sleep(3000);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. System.out.println(Thread.currentThread().getName() + " index:" + index);
  19. }
  20. });
  21. }
  22. try {
  23. Thread.sleep(4000);
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. }
  27. System.out.println("4秒后...");
  28. cachedExecutor.shutdown();
  29. }
  30. }

打印结果:

  1. pool-1-thread-1 index:0
  2. pool-1-thread-6 index:5
  3. pool-1-thread-5 index:4
  4. pool-1-thread-4 index:3
  5. pool-1-thread-3 index:2
  6. pool-1-thread-2 index:1
  7. 4秒后...

newScheduledThreadPool

定长线程池,可执行周期性的任务测试代码:

  1. public class TestThreadPool {
  2. //定长线程池,可执行周期性的任务
  3. static ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(3);
  4. public static void main(String[] args) {
  5. testScheduledExecutor();
  6. }
  7. //测试定长、可周期执行的线程池
  8. private static void testScheduledExecutor() {
  9. for (int i = 0; i < 3; i++) {
  10. final int index = i;
  11. //scheduleWithFixedDelay 固定的延迟时间执行任务;scheduleAtFixedRate 固定的频率执行任务
  12. scheduledExecutor.scheduleWithFixedDelay(new Runnable() {
  13. public void run() {
  14. System.out.println(Thread.currentThread().getName() + " index:" + index);
  15. }
  16. }, 0, 3, TimeUnit.SECONDS);
  17. }
  18. try {
  19. Thread.sleep(4000);
  20. } catch (InterruptedException e) {
  21. e.printStackTrace();
  22. }
  23. System.out.println("4秒后...");
  24. scheduledExecutor.shutdown();
  25. }
  26. }

打印结果:

  1. pool-1-thread-1 index:0
  2. pool-1-thread-2 index:1
  3. pool-1-thread-3 index:2
  4. pool-1-thread-1 index:0
  5. pool-1-thread-3 index:1
  6. pool-1-thread-1 index:2
  7. 4秒后...

newSingleThreadExecutor

单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行测试代码:

  1. public class TestThreadPool {
  2. //单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行
  3. static ExecutorService singleExecutor = Executors.newSingleThreadExecutor();
  4. public static void main(String[] args) {
  5. testSingleExecutor();
  6. }
  7. //测试单线程的线程池
  8. private static void testSingleExecutor() {
  9. for (int i = 0; i < 3; i++) {
  10. final int index = i;
  11. singleExecutor.execute(new Runnable() {
  12. public void run() {
  13. try {
  14. Thread.sleep(3000);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. System.out.println(Thread.currentThread().getName() + " index:" + index);
  19. }
  20. });
  21. }
  22. try {
  23. Thread.sleep(4000);
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. }
  27. System.out.println("4秒后...");
  28. singleExecutor.shutdown();
  29. }
  30. }

打印结果:

  1. pool-1-thread-1 index:0
  2. 4秒后...
  3. pool-1-thread-1 index:1
  4. pool-1-thread-1 index:2

newSingleThreadScheduledExecutor

单线程可执行周期性任务的线程池测试代码:

  1. public class TestThreadPool {
  2. //单线程可执行周期性任务的线程池
  3. static ScheduledExecutorService singleScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
  4. public static void main(String[] args) {
  5. testSingleScheduledExecutor();
  6. }
  7. //测试单线程可周期执行的线程池
  8. private static void testSingleScheduledExecutor() {
  9. for (int i = 0; i < 3; i++) {
  10. final int index = i;
  11. //scheduleWithFixedDelay 固定的延迟时间执行任务;scheduleAtFixedRate 固定的频率执行任务
  12. singleScheduledExecutor.scheduleAtFixedRate(new Runnable() {
  13. public void run() {
  14. System.out.println(Thread.currentThread().getName() + " index:" + index);
  15. }
  16. }, 0, 3, TimeUnit.SECONDS);
  17. }
  18. try {
  19. Thread.sleep(4000);
  20. } catch (InterruptedException e) {
  21. e.printStackTrace();
  22. }
  23. System.out.println("4秒后...");
  24. singleScheduledExecutor.shutdown();
  25. }
  26. }

打印结果:

  1. pool-1-thread-1 index:0
  2. pool-1-thread-1 index:1
  3. pool-1-thread-1 index:2
  4. pool-1-thread-1 index:0
  5. pool-1-thread-1 index:1
  6. pool-1-thread-1 index:2
  7. 4秒后...

newWorkStealingPool

任务窃取线程池,不保证执行顺序,适合任务耗时差异较大。线程池中有多个线程队列,有的线程队列中有大量的比较耗时的任务堆积,而有的线程队列却是空的,就存在有的线程处于饥饿状态,当一个线程处于饥饿状态时,它就会去其它的线程队列中窃取任务。解决饥饿导致的效率问题。默认创建的并行 level 是 CPU 的核数。主线程结束,即使线程池有任务也会立即停止。测试代码:

  1. public class TestThreadPool {
  2. //任务窃取线程池
  3. static ExecutorService workStealingExecutor = Executors.newWorkStealingPool();
  4. public static void main(String[] args) {
  5. testWorkStealingExecutor();
  6. }
  7. //测试任务窃取线程池
  8. private static void testWorkStealingExecutor() {
  9. for (int i = 0; i < 10; i++) {//本机 CPU 8核,这里创建10个任务进行测试
  10. final int index = i;
  11. workStealingExecutor.execute(new Runnable() {
  12. public void run() {
  13. try {
  14. Thread.sleep(3000);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. System.out.println(Thread.currentThread().getName() + " index:" + index);
  19. }
  20. });
  21. }
  22. try {
  23. Thread.sleep(4000);//这里主线程不休眠,不会有打印输出
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. }
  27. System.out.println("4秒后...");
  28. // workStealingExecutor.shutdown();
  29. }
  30. }

打印结果如下,index:8,index:9并未打印出:

  1. ForkJoinPool-1-worker-1 index:0
  2. ForkJoinPool-1-worker-7 index:6
  3. ForkJoinPool-1-worker-5 index:4
  4. ForkJoinPool-1-worker-3 index:2
  5. ForkJoinPool-1-worker-4 index:3
  6. ForkJoinPool-1-worker-2 index:1
  7. ForkJoinPool-1-worker-0 index:7
  8. ForkJoinPool-1-worker-6 index:5
  9. 4秒后...

线程池的工作流程

  1. 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行他们。
  2. 当调用execute()方法添加一个任务时,线程池会做如下判断:a. 如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务b. 如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列c. 如果这时候队列满了,而且正在运行的线程数量小于maximunPoolSize,那么还是要创建非核心线程立刻运行这个任务d. 如果队列满了,而且正在运行的线程数量大于或等于maximunPoolSize,那么线程池会抛出RejectedExecutionException
  3. 当一个线程完成任务时,它会从队列中取下一个任务来执行
  4. 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到corePoolSize的大小

可以用如下图来表示整体流程image.png

以太坊cppgolang区别 编程

以太坊cppgolang区别

以太坊是一种去中心化的开源平台,它采用智能合约技术,旨在构建和运行不受干扰的分布式应用程序。作为目前最受欢迎的区块链平台之一,以太坊提供了多种编程语言的支持,其
progolang 编程

progolang

Go语言(Golang)是由Google开发的一门静态类型编程语言。作为一名专业的Golang开发者,我深知这门语言的优势和特点。在本文中,我将介绍Golang
golangn个发送者 编程

golangn个发送者

Golang是一种开源的编程语言,由Google团队开发,旨在提高程序的并发性和简化软件开发过程。在Go语言中,有时需要向多个接收者发送信息。本文将介绍如何在G
golang技能图谱 编程

golang技能图谱

从互联网行业的快速发展到人工智能技术的日益成熟,各种编程语言也应运而生。而在这众多的编程语言中,Golang(即Go)作为一门强大且高效的开发语言备受关注。Go
评论:0   参与:  8