线程池分类总结

目录

概述

FixedThreadPool线程池

CachedThreadPool线程池

ScheduledThreadPool线程池 

singleThreadPool 

总结

FixedThreadPool

CachedThreadPool

SingleThreadExecutor

ScheduledThreadPool

线程池使用注意事项(重要!!!!!!)


概述

Java标准库中为我们提供了几种常用的线程池,创建这些线程池的方法都被封装到Executors工具类中

  • FixedThreadPool: 线程数量固定的线程池,使用Executors.newFixedThreadPool()创建;
  • CachedThreadPool:线程数根据任务动态调整的线程池,使用Executors.newCachedThreadPool()创建;
  • SingleThreadExecutor: 仅提供一个单线程的线程池,使用Executors.newSingleThreadExecutor()来创建;
  • ScheduledThreadPool: 能实现定时,周期性任务的线程池,使用Executors.newScheduledThreadPool来创建。

FixedThreadPool线程池

线程数固定的线程池

下面是FixedThreadPool线程池的使用案例:

public class Main {
    public static void main(String[] args) {
         // 创建一个固定大小的线程池:
         ExecutorService executorService = Executors.newFixedThreadPool(4);

         for (int i = 0; i < 6; i++) {
         executorService.execute(new Task("线程"+i));
         }
         // 关闭线程池:
         executorService.shutdown();
     }
}
class Task implements Runnable {
    private String taskName;
    public Task(String taskName) {
        this.taskName = taskName;
    }
     @Override
     public void run() {
         System.out.println("启动线程 ===> " + this.taskName);
         try {
             Thread.sleep(1000);
         } catch (InterruptedException e) {
         }
     System.out.println("结束线程 <= " + this.taskName);
     }
}

 执行结果:

启动线程 ===> 线程2

启动线程 ===> 线程3

启动线程 ===> 线程0

启动线程 ===> 线程1

结束线程 <= 线程2

结束线程 <= 线程3

结束线程 <= 线程1

结束线程 <= 线程0

启动线程 ===> 线程5

启动线程 ===> 线程4

结束线程 <= 线程4

结束线程 <= 线程5

结果分析: 

由于使用的线程池为固定数量,因此只有前四个线程任务会同时执行,每个任务被分配一个线程。 

剩下的两个线程任务只能在阻塞队列中等待,等到有空闲线程的时候才会被分配线程并执行。

CachedThreadPool线程池

线程数根据任务数量动态调整的线程池

使用CachedThreadPool观察运行结果:

ExecutorService executorService = Executors.newCachedThreadPool();

启动线程 => 线程1

启动线程 => 线程5

启动线程 => 线程2

启动线程 => 线程4

启动线程 => 线程0

启动线程 => 线程3

结束线程 <= 线程4

结束线程 <= 线程1

结束线程 <= 线程5

结束线程 <= 线程0

结束线程 <= 线程3

结束线程 <= 线程2

结果分析:

我们看到,由于CachedThreadPool会根据任务数量动态调整线程池的大小,所以6个任务可以同时执行。

ScheduledThreadPool线程池 

能实现定时、周期性任务的线程池

  • 例如: 每秒刷新证券价格,定期发送短信或者邮件,这种任务本身固定,需要反复执行的,可以使用ScheduledThreadPool;
  • 放入ScheduledThreadPool的任务可以定期反复执行。

创建定时任务线程池ScheduledThreadPool :

ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);

 延迟三秒钟后执行,任务只执行1次

executorService.schedule(new Task("线程A"), 3, TimeUnit.SECONDS);

延迟两秒钟后,每隔三秒钟执行任务1次

// 方式1
executorService.scheduleAtFixedRate(new Task("线程A"), 2,3, TimeUnit.SECONDS);

// 方式2
executorService.scheduleWithFixedDelay(new Task("线程A"), 2,3, TimeUnit.SECONDS);

分别由两种延迟方法,它们对执行间隔的定义有所不同:

  1. FixedRate: 是指任务总是以固定时间间隔触发,不管任务执行多长时间,只要到了设置好的时间,就会再次执行线程任务;
  2. FixedDelay: 是指在上一次任务执行完毕之后,等待固定的时间间隔,然后再执行下一次任务。

 

singleThreadPool 

仅提供单线程,这样可以保证在多线程的环境下,使线程任务得到一定的顺序执行。

下面是使用singleThreadPool 来执行线程任务的案例:

public class Demo01 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for(int i=0;i<10;i++){
            executorService.execute(new TaskThread("线程任务"+i));
        }
        executorService.shutdown();
    }
}
class TaskThread implements Runnable{

    private String TaskName;

    public TaskThread(String taskName){
        this.TaskName = taskName;
    }

    @Override
    public void run() {
        System.out.println("线程任务被执行=====>"+ TaskName);

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("线程任务结束=====>"+TaskName);
    }
}

执行结果:

我们可以看出,这10个线程任务分别按照顺序执行,这也是 singleThreadPool这个线程池特点的体现。

总结

FixedThreadPool

线程数固定的线程池

线程池参数:

  • 核心线程数和最大线程数相等;
  • 非核心线程空闲存活时间keepAliveTime为0;
  • 阻塞队列为无界队列LinkedBlockingQueue。

 CachedThreadPool

可缓存线程池,线程数根据任务动态调整的线程池

线程池参数:

  • 核心线程数为0;
  • 最大线程数是Integer.MAX_VALUE;
  • 工作队列是SynchronousQueue同步队列;
  • 非核心线程存活时间为60秒。

工作机制:

  • 提交线程任务;
  • 因为核心线程数为0,所以直接加到工作队列;
  • 判断是否有空闲线程,如果有则将任务取出并执行;
  • 如果没有,则新建线程执行任务;
  • 执行完任务的空闲线程存活时间为60秒,在这期间还可以处理别的线程任务,超过时间则销毁。 

使用场景: 用与并发执行大量短期的小任务。 

SingleThreadExecutor

单线程化的线程池

线程池参数:

  • 核心线程数和最大线程数为1;
  • 阻塞队列是LinkedBlockingQueue;
  • 非核心线程空闲存活时间为0秒。

工作机制: 每次处理一个线程任务,其他线程任务在阻塞队列中等待。

使用场景: 适用于串行执行任务的场景,将任务按顺序执行。

ScheduledThreadPool

能定时,周期性的执行线程任务的线程池

线程池参数:

  • 最大线程数为Integer.MAX_VALUE;
  • 阻塞队列是DelayedWorkQueue;
  • keepAliveTime为0。

使用场景: 周期性地执行任务,并且需要限制线程数量的需求场景。

线程池使用注意事项(重要!!!!!!)

在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用Executors去创建,而要通过ThreadPoolExecutor方式。jdk中Executor框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过new ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。
必须为线程池中的线程,按照业务规则,进行命名。可以在创建线程池时,使用自定义线程工厂规范线程命名方式,避免线程使用默认名称。

不同的线程池其实都是根据new ThreadPool()来传入不同的参数,组合在一起形成了各种不同功能的线程池。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值