博主信息
富贵人生
博文
87
粉丝
0
评论
0
访问量
3209
积分:0
P豆:174

Executors创建线程池有哪几种方式?

2021年10月15日 22:29:17阅读数:22博客 / 富贵人生

Executors如何创建线程池?

Executors 类是从 JDK 1.5 开始就新增的线程池创建的静态工厂类,它就是创建线程池的,但是很多的大厂已经不建议使用该类去创建线程池。原因在于,该类创建的很多线程池的内部使用了无界任务队列,在并发量很大的情况下会导致 JVM 抛出 OutOfMemoryError,直接让 JVM 崩溃,影响严重。

 

但是 Executors 类究竟是如何使用的?

1. newFixedThreadPool

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

package com.yiidian.concurrency.a011;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/**
* 测试创建定长线程池
* @author yiidian
*/public class TestNewFixedThreadPool {    public static void main(String[] args) {        //创建工作线程数为 3 的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程
       ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);        //提交 6 个任务
       for (int i = 0; i <6; i++) {            final int index = i;
           fixedThreadPool.execute(() -> {                try {                    //休眠 3 秒
                   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秒后...");        
       //关闭线程池后,已提交的任务仍然会执行完
       fixedThreadPool.shutdown();
   }
   
}

打印结果:

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

 

2. newCachedThreadPool

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

package com.yiidian.concurrency.a011;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/**
* 测试创建可缓存的线程池
* @author yiidian
*/public class TestNewCachedThreadPool {    
   public static void main(String[] args) {        //创建可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制
       ExecutorService cachedThreadPool = Executors.newCachedThreadPool();        for (int i = 0; i <6; i++) {            final int index = i;
           cachedThreadPool.execute(() -> {                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秒后...");
       
       cachedThreadPool.shutdown();
       
   }
   
}

打印结果可以看出,创建的线程数与任务数相等

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

 

3. newScheduledThreadPool

创建定长线程池,可执行周期性的任务。

package com.yiidian.concurrency.a011;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;/**
* 测试创建定长线程池,可执行周期性的任务
* @author yiidian
*/public class TestNewScheduledThreadPool {    public static void main(String[] args) {        //创建定长线程池,可执行周期性的任务
       ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);        
       for (int i = 0; i <3; i++) {            final int index = i;            //scheduleWithFixedDelay 固定的延迟时间执行任务; scheduleAtFixedRate 固定的频率执行任务
           scheduledThreadPool.scheduleWithFixedDelay(() -> {
                   System.out.println(Thread.currentThread().getName() + " index:" + index);
           }, 0, 3, TimeUnit.SECONDS);
       }        
       try {
           Thread.sleep(4000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("4秒后...");
       
       scheduledThreadPool.shutdown();

   }
}

打印结果:

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

 

4. newSingleThreadExecutor

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

package com.yiidian.concurrency.a011;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/**
* 测试单线程的线程池
* @author yiidian
*/public class TestNewSingleThreadExecutor {    
   public static void main(String[] args) {        //单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行
       ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();        
       //提交 3 个任务
       for (int i = 0; i <3; i++) {            final int index = i;
           singleThreadPool.execute(() -> {                
               //执行第二个任务时,报错,测试线程池会创建新的线程执行任务三
               if (index == 1) {                    throw new RuntimeException("线程执行出现异常");
               }                
               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秒后...");
       
       singleThreadPool.shutdown();
   }

}

打印结果可以看出,即使任务出现了异常,游戏账号拍卖地图线程池还是会自动补充一个线程继续执行下面的任务

pool-1-thread-1 index:0Exception in thread "pool-1-thread-1" java.lang.RuntimeException: 线程执行出现异常
   at constxiong.concurrency.a011.TestNewSingleThreadExecutor.lambda$0(TestNewSingleThreadExecutor.java:21)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
   at java.lang.Thread.run(Thread.java:748)4秒后...
pool-1-thread-2 index:2

 

5. newSingleThreadScheduledExecutor

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

package com.yiidian.concurrency.a011;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;/**
* 测试单线程可执行周期性任务的线程池
* @author yiidian
*/public class TestNewSingleThreadScheduledExecutor {    public static void main(String[] args) {        //创建单线程可执行周期性任务的线程池
       ScheduledExecutorService singleScheduledThreadPool = Executors.newSingleThreadScheduledExecutor();        
       //提交 3 个固定频率执行的任务
       for (int i = 0; i <3; i++) {            final int index = i;            //scheduleWithFixedDelay 固定的延迟时间执行任务; scheduleAtFixedRate 固定的频率执行任务
           singleScheduledThreadPool.scheduleAtFixedRate(() -> {
               System.out.println(Thread.currentThread().getName() + " index:" + index);
           }, 0, 3, TimeUnit.SECONDS);
       }        
       try {
           Thread.sleep(4000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("4秒后...");
       
       singleScheduledThreadPool.shutdown();
   }
   
}

打印机结果可以看出 0-2 任务都被执行了 2 个周期

pool-1-thread-1 index:0pool-1-thread-1 index:1pool-1-thread-1 index:2pool-1-thread-1 index:0pool-1-thread-1 index:1pool-1-thread-1 index:24秒后...

 

6. newWorkStealingPool

创建任务可窃取线程池,空闲线程可以窃取其他任务队列的任务,不保证执行顺序,适合任务耗时差异较大。

package com.yiidian.concurrency.a011;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/**
* 测试可任务窃取线程池
* @author yiidian
*/public class TestNewWorkStealingPool {    public static void main(String[] args) {        //创建 4个工作线程的 任务可窃取线程池,如果不设置并行数,默认取 CPU 总核数
       ExecutorService workStealingThreadPool = Executors.newWorkStealingPool(4);        
       for (int i = 0; i <10; i++) {            final int index = i;
           workStealingThreadPool.execute(() -> {                try {                    //模拟任务执行时间为 任务编号为0 1 2 的执行时间需要 3秒;其余任务200 毫秒,导致任务时间差异较大
                   if (index <= 2) {
                       Thread.sleep(3000);
                   } else {
                       Thread.sleep(200);
                   }
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               System.out.println(Thread.currentThread().getName() + " index:" + index);
           });
       }        
       try {
           Thread.sleep(10000);//休眠 10 秒
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("10秒后...");
   }
   
}

打印结果可以看出,线程 ForkJoinPool-1-worker-0 把3-9的任务都执行完

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


版权申明:本博文版权归博主所有,转载请注明地址!如有侵权、违法,请联系admin@php.cn举报处理!

全部评论

文明上网理性发言,请遵守新闻评论服务协议

条评论
  • java线的四是:1、newCachedThreadPool一个可缓存线;2、newFixedThreadPool一个定长线;3、newScheduledThreadPool