欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

线程池

程序员文章站 2023-04-03 09:45:47
继承Thread的弊端 1.每次new Thread的时候都需要新建一个线程,性能差 2.线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM 3.Thread类缺少更多功能,比如更多的执行、定期执行、线程中断。 线程池的好处 1.重用存在的线程,减少对象创建、 ......

继承Thread的弊端

1.每次new Thread的时候都需要新建一个线程,性能差

2.线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM

3.Thread类缺少更多功能,比如更多的执行、定期执行、线程中断。

线程池的好处

1.重用存在的线程,减少对象创建、消亡的开销、性能佳

2.可以有效的控制最大并发线程数,提高系统资源利用率,同时可以避免过多资源竞争,避免阻塞。

3.提供定时执行、定期执行、单线程、并发数控制等功能。

 

线程池-ThreadPoolExecutor

参数说明:ThreadPoolExecutor一共有七个参数,这七个参数配合起来,构成了线程池强大的功能。

corePoolSize:核心线程数线程池的基本大小,即在没有任务需要执行的时候线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。这里需要注意的是:在刚刚创建ThreadPoolExecutor的时候,线程并不会立即启动,而是要等到有任务提交时才会启动,除非调用了prestartCoreThread/prestartAllCoreThreads事先启动核心线程。

maximumPoolSize:线程最大线程数,线程池中允许的最大线程数,线程池中的当前线程数目不会超过该值。如果队列中任务已满,并且当前线程个数小于maximumPoolSize,那么会创建新的线程来执行任务。

workQueue : 阻塞队列,存储等待执行的任务,很重要,会对线程池运行过程产生重大影响

线程池

线程池

ThreadPoolExecutorexecute方法分下面4种情况。
1)如果当前运行的线程少于corePoolSize则创建新线程来行任(注意,一步骤需要取全局)。
2)如果运行的线程等于或多于corePoolSize将任加入BlockingQueue
3)如果无法将任加入BlockingQueue列已),则创建新的线程来理任(注意,执行一步需要取全局)。
4)如果建新线程将使当前运行的线程超出maximumPoolSize,任将被拒,并用RejectedExecutionHandler.rejectedExecution()方法。

线程池大小调节策略。通过corePoolSize和maximumPoolSize,控制如何新增线程;通过allowCoreThreadTimeOut和keepAliveTime,控制如何销毁线程。

allowCoreThreadTimeOut:

该属性用来控制是否允许核心线程超时退出。如果线程池的大小已经达到了corePoolSize,不管有没有任务需要执行,线程池都会保证这些核心线程处于存活状态。可以知道:该属性只是用来控制核心线程的。

keepAliveTime:

如果一个线程处在空闲状态的时间超过了该属性值,就会因为超时而退出。举个例子,如果线程池的核心大小corePoolSize=5,而当前大小poolSize =8,那么超出核心大小的线程,会按照keepAliveTime的值判断是否会超时退出。如果线程池的核心大小corePoolSize=5,而当前大小poolSize =5,那么线程池中所有线程都是核心线程,这个时候线程是否会退出,取决于allowCoreThreadTimeOut。

unit : keepAliveTime的时间单位

threadFactory:线程工厂,用来创建线程

rejectHandler:当拒绝处理任务时的策略

线程池

  • running:能接受新提交的任务,也能处理阻塞队列中的任务
  • shutdown:不能处理新的任务,但是能继续处理阻塞队列中任务
  • stop:不能接收新的任务,也不处理队列中的任务
  • tidying:如果所有的任务都已经终止了,这时有效线程数为0
  • terminated:最终状态
序号 方法名 描述
1 execute() 提交任务,交给线程池执行
2 submit() 提交任务,能够返回执行结果 execute+Future
3 shutdown() 关闭线程池,等待任务都执行完
4 shutdownNow() 关闭线程池,不等待任务执行完
5 getTaskCount() 线程池已执行和未执行的任务总数
6 getCompleteTaskCount() 已完成的任务数量
7 getPoolSize() 线程池当前的线程数量
8 getActiveCount()

当前线程池中正在执行任务的线程数量

使用Executor创建线程池

使用Executor可以创建四种线程池:分别对应上边提到的四种线程池初始化方法

1、Executors.newCachedThreadPool 
创建一个可缓存的线程池,如果线程池的长度超过了处理的需要,可以灵活回收空闲线程。如果没有可回收的就新建线程。

//使用方法:
public static void main(String[] args) {
    ExecutorService executorService = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++) {
        final int index = i;
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                log.info("task:{}", index);
            }
        });
    }
    executorService.shutdown();
}

 

值得注意的一点是,newCachedThreadPool的返回值是ExecutorService类型,该类型只包含基础的线程池方法,但却不包含线程监控相关方法,因此在使用返回值为ExecutorService的线程池类型创建新线程时要考虑到具体情况。 

2、newFixedThreadPool 
定长线程池,可以线程现成的最大并发数,超出在队列等待

//使用方法:
public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 10; i++) {
        final int index = i;
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                log.info("task:{}", index);
            }
        });
    }
    executorService.shutdown();
}

3、newSingleThreadExecutor 
单线程化的线程池,用唯一的一个共用线程执行任务,保证所有任务按指定顺序执行(FIFO、优先级…)

//使用方法:
public static void main(String[] args) {
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 10; i++) {
        final int index = i;
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                log.info("task:{}", index);
            }
        });
    }
    executorService.shutdown();
}

4、newScheduledThreadPool 
定长线程池,支持定时和周期任务执行

//基础使用方法:
public static void main(String[] args) {
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
    executorService.schedule(new Runnable() {
        @Override
        public void run() {
            log.warn("schedule run");
        }
    }, 3, TimeUnit.SECONDS);//延迟3秒执行
    executorService.shutdown();
}

小扩展:延迟执行任务的操作,java中还有Timer类同样可以实现

Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        log.warn("timer run");
    }
}, new Date(), 5 * 1000);