栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java线程池

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java线程池

(一)什么是线程池

线程池顾名思义就是存放线程的池子。要使用线程的时候直接从池子中取就可以了,这样有啥好处呢?咱们可以通过一个类比来理解。
在以前没有自来水的时候,都是到很远的地方挑水做饭,洗衣,但是每次要使用的时候都要花时间去挑水,等水挑来了可能累得已经不想煮饭洗衣。所以我们一般会在院子里面建造一个水池或者是放一个水缸,每次有空的时候把水装满,下次要用的时候,直接从水池或者是水缸中取。这样就可以在每次急于使用水的时候能及时用到,而不是还要花时间去挑水

线程池也是一样,先把一些线程创建出来放到池中,使用的时候直接取就可以了。因为创建线程和销毁线程是要耗时的。

(二)使用线程池有什么好处

你是不是看过有些项目中的线程随便创建,到处在创建,Java的匿名线程的创建使用更是让这种风气盛行。

  new Thread(new Runnable() {
            @Override
            public void run() {
                //TODO:do something
            }
        }).start();

这种代码是不是很熟悉?其实在小型项目中这样写的确不会引起啥大问题,但是到大型项目中,这样的线程写多了会导致性能受到影响。这时线程池的作用就体现出来了,使用线程池可以减少线程在创建和销毁上耗费的时间以及系统开销。也可以解决资源不足的问题,因为创建线程也需要耗费空间的。线程池的好处总结起来就是三点:

1. 重用已经存在的线程,减少对象在创建,消亡的开销,能够优化性能
2. 可以有效的控制最大并发线程数,提高系统资源的使用率,同时避免过多的资源竞争,避免线程阻塞
3. 线程池可以提供定时执行,定期执行,单线程,并发数控制等

(三)线程池中各个参数的理解
 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {

corePoolSize:核心线程数,线程池的基本大小,会一直存活
maximumPoolSize:最大线程数:先吃池最大线程大小,当活动线程达到这个值后,后续的任务会被阻塞
keepAliveTime:空闲线程的存活时间,超过了这个时长,空闲的非核心线程就会被回收。
TimeUnit unit:他标记keepAliveTime的单位,比如是秒,毫秒啥的,比如keepAliveTime为1,unit为SECOND,就表示1秒
workQueue:任务队列,通过线程池的execute()方法提交的Runnable对象会存储在这个参数中,用于存放任务的阻塞队列
handler:当队列和最大线程数都满了之后的缓存策略。

(四)Android中常见的线程池

在Android中的线程池常见的有四种:

  1. newCachedThreadPool:
   public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue(),
                                      threadFactory);
    }

线程池中只有非核心线程,最大线程数非常大。当所有线程都活动时会为新任务创建新线程,否则会使用空闲线程处理任务,但是线程池中的空闲线程只会有60秒到存活时间,过了就会被回收,它的优点就是任何任务都会被立即执行,比较适合执行大量耗时较少的任务。

  1. newFixedThreadPool:
  public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue());
    }

只有固定数量的核心线程,当所有的线程都在活动的时候,因为队列没有限制大小,所以新任务会等待执行,线程空闲时不会释放空工作线程,还会占用一定的系统资源,他的优点就是可以更快的响应外界的请求,因为线程一直是存活的,省去了创建线程和销毁线程的时间,当有空闲线程时新任务马上就可以得到处理

  1. newScheduledThreadPool:
   public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }

核心线程数固定,非核心线程没有限制,但是空闲的线程会立即被回收,他的优点就是可以执行定时任务以及有固定周期的重复任务

  1. newSingleThreadExecutor:
  public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue()));
    }

只有一个核心线程,所有的任务都在同一线程中按序完成,他的优点也很明显,那就是不需要处理线程同步的问题。

(五)线程池ThreadPoolExecutor的工作策略

面试的时候这个点经常会被问到,ThreadPoolExecutor执行任务时会遵循如下规则:
(1)如果线程池中的数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务。
(2)如果线程池中的线程数量已经达到或者超过了核心线程的数量,那么任务会被插入任务队列中排队等待执行
(3)如果任务队列已经满了,无法将任务插入到任务队列中,这时候如果线程数量没有达到最大线程数,会立刻启动一个非核心线程来执行任务
(4)如果线程数量已经达到了最大线程数,那么就会拒绝执行此任务,然后ThreadPoolExecutor会调用RejectedExecutionHandler的rejectedExection方法通知调用者。

(六)如何选择线程池

好的线程池能够很好的提高系统的整体性能,达到优化性能的目的,但是设计不好的线程池则可能会对系统有害无益。那么应该如何选择线程池呢?应该分场景来看
场景一:高并发和任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换,因为线程切换上下文会很耗时。

场景二:并发不高、任务执行时间长的业务要区分开看:

(1)假如是IO密集型的任务,也就是业务时间大多数都是集中在IO操作上,因为IO操作并不占用CPU,所以我们应该让CPU忙起来,这时候我们可以加大线程池中的线程数目,让CPU处理更多的业务

(2)假如是计算密集型任务,任务的执行时间大多数集中在计算操作上,减少线程上下文的切换,将线程池中的线程数设置得少一些,

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1003451.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号