多线程之创建线程池

雨点打透心脏的1/2处 2022-02-04 08:21 482阅读 0赞

直接new出来,使用ThreadPoolExecutor

查看源码,可以看到,这个类有4个构造方法在这里插入图片描述
这里我们挑最复杂的一个讲解一下各个参数的含义,先看源码

  1. public ThreadPoolExecutor(int corePoolSize,
  2. int maximumPoolSize,
  3. long keepAliveTime,
  4. TimeUnit unit,
  5. BlockingQueue<Runnable> workQueue,
  6. ThreadFactory threadFactory,
  7. RejectedExecutionHandler handler) {
  8. if (corePoolSize < 0 ||
  9. maximumPoolSize <= 0 ||
  10. maximumPoolSize < corePoolSize ||
  11. keepAliveTime < 0)
  12. throw new IllegalArgumentException();
  13. if (workQueue == null || threadFactory == null || handler == null)
  14. throw new NullPointerException();
  15. this.corePoolSize = corePoolSize;
  16. this.maximumPoolSize = maximumPoolSize;
  17. this.workQueue = workQueue;
  18. this.keepAliveTime = unit.toNanos(keepAliveTime);
  19. this.threadFactory = threadFactory;
  20. this.handler = handler;
  21. }
  22. public ThreadPoolExecutor(int corePoolSize,
  23. int maximumPoolSize,
  24. long keepAliveTime,
  25. TimeUnit unit,
  26. BlockingQueue<Runnable> workQueue,
  27. ThreadFactory threadFactory,
  28. RejectedExecutionHandler handler) {
  29. if (corePoolSize < 0 ||
  30. maximumPoolSize <= 0 ||
  31. maximumPoolSize < corePoolSize ||
  32. keepAliveTime < 0)
  33. throw new IllegalArgumentException();
  34. if (workQueue == null || threadFactory == null || handler == null)
  35. throw new NullPointerException();
  36. this.corePoolSize = corePoolSize;
  37. this.maximumPoolSize = maximumPoolSize;
  38. this.workQueue = workQueue;
  39. this.keepAliveTime = unit.toNanos(keepAliveTime);
  40. this.threadFactory = threadFactory;
  41. this.handler = handler;
  42. }
  • corePoolSize : 核心池的大小,在创建后,如果我们没有调用prestartAllCoreThreads()或prestartCoreThread()这两个预创建线程的方法,那么线程池中是没有线程的,直到有任务来才会有建立线程去执行,如果线程数达到了核心池的大小,就会把任务放到队列中去执行
  • maximumPoolSize :最大线程数,当线程数达到了核心池的大小,并且,队列满了,注意,一定是队列满了才会新开线程取执行任务,此时线程池中线程的个数是大于核心池大小的。当线程池中线程个数等于最大线程数时,并且队列也满了,这时候会根据饱和策略RejectedExecutionHandler拒绝新的任务。
  • keepAliveTime : 线程保持存活的时间,也就是一个线程在多久没有执行任务的情况下会自动销毁。默认情况下,当线程个数大于核心池大小的时候,才会触发这个属性,一直到线程个数不超过核心池大小。比如核心池是10,现在空闲线程有15个,那么会将线程降到10个,才停止。但是,有一个allowCoreThreadTimeOut(boolean)方法,如果调用这个方法,就不会管核心池大小,比如核心池是10,现在空闲线程有15个,会一直降到0;比如核心池是10,现在空闲线程有8个,也会一直降到0。
  • unit : 时间的单位:

    TimeUnit.DAYS; //天
    TimeUnit.HOURS; //小时
    TimeUnit.MINUTES; //分钟
    TimeUnit.SECONDS; //秒
    TimeUnit.MILLISECONDS; //毫秒
    TimeUnit.MICROSECONDS; //微妙
    TimeUnit.NANOSECONDS; //纳秒

  • workQueue :阻塞队列:常用的有3种:

    1)ArrayBlockingQueue:先进先出,基于数组结构,创建时必须指定大小;

    2)LinkedBlockingQueue:先进先出,基于链表,如果创建时没有指定队列大小,则默认为Integer.MAX_VALUE,2^31 - 1;

    3)synchronousQueue:不保存提交的任务,而是直接新建一个线程来执行新来的任务。

  • threadFactory:线程工厂,只是用来生产线程的,实际意义不大,默认的就行。
  • handler :拒绝策略:

    1)ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
    2)ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
    3)ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
    4)ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

我们写个demo看一下如何new一个线程池

  1. public static void main(String[] args) throws Exception{
  2. ThreadPoolExecutor executor = new ThreadPoolExecutor(
  3. //核心线程数5个,最大线程数10个,活跃时间30,单位秒
  4. 5, 10, 30, TimeUnit.SECONDS,
  5. // 数组堵塞队列,大小为100
  6. new ArrayBlockingQueue<>(100),
  7. //线程工程
  8. new ThreadFactory() {
  9. @Override
  10. public Thread newThread(Runnable r) {
  11. Thread thread = new Thread(r);
  12. return thread;
  13. }
  14. },
  15. // 拒绝策略
  16. new ThreadPoolExecutor.DiscardPolicy());
  17. }

当使用结束后,调用方法关闭线程池,这里提供了两个方法

1)shutdown():不会立即终止线程池,要等所有堵塞队列中的任务都执行完后才终止,此时无法再往队列中加入新任务

2)shutdownNow():立即终止线程池,并尝试终止正在执行的任务,清空堵塞队列,有返回值,是尚未执行的任务

使用Executors类中提供的静态方法创建线程池

先看源码,,一共提供了以下的静态方法,其实看源码,本质还是调用的第一种方法,但是已经封装好了,这里java官方文档建议我们使用这种方法创建线程池,因为简单,不容易出错。
在这里插入图片描述
我们先说几个常用的。具体内容以后慢慢补充

  • newCachedThreadPool : 创建一个可缓存的线程池
  • newWorkStealingPool :以后补充
  • newFixedThreadPool :定长线程池,超出线程在队列中等待
  • newScheduledThreadPool : 定长线程池,用于定时及周期性任务执行
  • newSingleThreadExecutor : 单线程线程

发表评论

表情:
评论列表 (有 0 条评论,482人围观)

还没有评论,来说两句吧...

相关阅读

    相关 java线线

    java多线程之线程池 池化技术 程序的运行,其本质上,是对系统资源(CPU、内存、磁盘、网络等等)的使用。如何高效的使用这些资源是我们编程优化演进的一个方向。今天说

    相关 线 线创建

    一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的。在jdk1.5之后这一情况有了很大的改观。Jdk1.

    相关 线线

    前言: 1. 系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互。在这种情形下,使用线程池可以很好地提高性能,尤其是当程序中需要创建大量生存期很短暂的线程时,