【315期】JDK1.8 创建线程池有哪几种方式?

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

【315期】JDK1.8 创建线程池有哪几种方式?

JDK1.8 创建线程池有哪几种方式?

  • newFixedThreadPool

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

测试代码:

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

打印结果:

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

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

测试代码:

public class TestThreadPool {
 
 //可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制
 static ExecutorService cachedExecutor = Executors.newCachedThreadPool();
 
 
 public static void main(String[] args) {
  testCachedExecutor();
 }
 
 //测试可缓存线程池
 private static void testCachedExecutor() {
  for (int i = 0; i < 6; i++) {
   final int index = i;
   cachedExecutor.execute(new Runnable() {
    public void run() {
     try {
      Thread.sleep(3000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
     System.out.println(Thread.currentThread().getName() + " index:" + index);
    }
   });
  }
  
  try {
   Thread.sleep(4000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  System.out.println("4秒后...");
  
  cachedExecutor.shutdown();
 }
 
}

打印结果:

pool-1-thread-1 index:0
pool-1-thread-6 index:5
pool-1-thread-5 index:4
pool-1-thread-4 index:3
pool-1-thread-3 index:2
pool-1-thread-2 index:1
4秒后...
  • newScheduledThreadPool 定长线程池,可执行周期性的任务

测试代码:

public class TestThreadPool {
 
 //定长线程池,可执行周期性的任务
 static ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(3);
 
 
 public static void main(String[] args) {
  testScheduledExecutor();
 }
 
 //测试定长、可周期执行的线程池
 private static void testScheduledExecutor() {
  for (int i = 0; i < 3; i++) {
   final int index = i;
   //scheduleWithFixedDelay 固定的延迟时间执行任务;scheduleAtFixedRate 固定的频率执行任务
   scheduledExecutor.scheduleWithFixedDelay(new Runnable() {
    public void run() {
     System.out.println(Thread.currentThread().getName() + " index:" + index);
    }
   }, 03, TimeUnit.SECONDS);
  }
  
  try {
   Thread.sleep(4000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  System.out.println("4秒后...");
  
  scheduledExecutor.shutdown();
 }
 
}

打印结果:

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

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

测试代码:

public class TestThreadPool {
 
 //单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行
 static ExecutorService singleExecutor = Executors.newSingleThreadExecutor();
 
 
 public static void main(String[] args) {
  testSingleExecutor();
 }
 
 //测试单线程的线程池
 private static void testSingleExecutor() {
  for (int i = 0; i < 3; i++) {
   final int index = i;
   singleExecutor.execute(new Runnable() {
    public void run() {
     try {
      Thread.sleep(3000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
     System.out.println(Thread.currentThread().getName() + " index:" + index);
    }
   });
  }
  
  try {
   Thread.sleep(4000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  System.out.println("4秒后...");
  
  singleExecutor.shutdown();
 }
 
}

打印结果:

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

单线程可执行周期性任务的线程池

测试代码:

public class TestThreadPool {
 
 //单线程可执行周期性任务的线程池
 static ScheduledExecutorService singleScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
 
 
 public static void main(String[] args) {
  testSingleScheduledExecutor();
 }
 
 //测试单线程可周期执行的线程池
 private static void testSingleScheduledExecutor() {
  for (int i = 0; i < 3; i++) {
   final int index = i;
   //scheduleWithFixedDelay 固定的延迟时间执行任务;scheduleAtFixedRate 固定的频率执行任务
   singleScheduledExecutor.scheduleAtFixedRate(new Runnable() {
    public void run() {
     System.out.println(Thread.currentThread().getName() + " index:" + index);
    }
   }, 03, TimeUnit.SECONDS);
  }
  
  try {
   Thread.sleep(4000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  System.out.println("4秒后...");
  
  singleScheduledExecutor.shutdown();
 }
 
}

打印结果:

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

任务窃取线程池,不保证执行顺序,适合任务耗时差异较大。

线程池中有多个线程队列,有的线程队列中有大量的比较耗时的任务堆积,而有的线程队列却是空的,就存在有的线程处于饥饿状态,当一个线程处于饥饿状态时,它就会去其它的线程队列中窃取任务。解决饥饿导致的效率问题。

默认创建的并行 level 是 CPU 的核数。主线程结束,即使线程池有任务也会立即停止。

测试代码:

public class TestThreadPool {
 
 //任务窃取线程池
 static ExecutorService workStealingExecutor = Executors.newWorkStealingPool();
 
 public static void main(String[] args) {
  testWorkStealingExecutor();
 }
 
 //测试任务窃取线程池
 private static void testWorkStealingExecutor() {
  for (int i = 0; i < 10; i++) {//本机 CPU 8核,这里创建10个任务进行测试
   final int index = i;
   workStealingExecutor.execute(new Runnable() {
    public void run() {
     try {
      Thread.sleep(3000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
     System.out.println(Thread.currentThread().getName() + " index:" + index);
    }
   });
  }
  
  try {
   Thread.sleep(4000);//这里主线程不休眠,不会有打印输出
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  System.out.println("4秒后...");
  
//  workStealingExecutor.shutdown();
 }
 
}

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

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

感谢阅读,希望对你有所帮助 🙂 

来源:blog.csdn.net/meism5/article/details/90261021

END

题外推荐

推荐一个“摸鱼程序员”聚集地


【315期】JDK1.8 创建线程池有哪几种方式?

【301期】面试官:dubbo为什么没有采用jdk的spi机制?

【302期】面试官:幂等性的接口该如何设计?

【303期】如何理解算法中的时间复杂度?

【304期】堆排序算法(图解详细流程)

【305期】面试官:Redis用过是吧?那你讲讲Redis都有哪些监控指标?

【306期】面试官:解决集群环境下定时任务多次执行的办法有哪些?

【307期】面试官:什么是NIO?NIO的原理是什么?

【308期】面试官:为什么kafka效率这么高?

【309期】阿里巴巴菜鸟网络——面试经历记录

【310期】面试官:MySQL主备、主从、读写分离你了解多少?


与其在网上拼命找题? 不如马上关注我们~

【315期】JDK1.8 创建线程池有哪几种方式?

PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。“在看”支持我们吧!

原文始发于微信公众号(Java面试题精选):【315期】JDK1.8 创建线程池有哪几种方式?