线程池ThreadPoolExecutor

Java基础

浏览数:96

2019-6-2

三月五号开学,这几天呆在学校闲着无聊,又不知道要写些什么,就随便写点线程池的东西吧。

(一) 线程池作用

线程池的作用就2个:

1、减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务

2、可以根据系统的承受能力,调整线程池中工作线程的数据,防止因为消耗过多的内存导致服务器崩溃

使用线程池,要根据系统的环境情况,手动或自动设置线程数目。少了系统运行效率不高,多了系统拥挤、占用内存多。用线程池控制数量,其他线程排队等候。一个任务执行完毕,再从队列中取最前面的任务开始执行。若任务中没有等待任务,线程池这一资源处于等待。当一个新任务需要运行,如果线程池中有等待的工作线程,就可以开始运行了,否则进入等待队列。

(二) 线程池类结构

1、最顶级的接口是Executor,不过Executor严格意义上来说并不是一个线程池而只是提供了一种任务如何运行的机制而已

2、ExecutorService才可以认为是真正的线程池接口,接口提供了管理线程池的方法

3、Executors是线程的工具类。可以用Executors创建线程池。

但Alibaba的命名规范里面的一段话:

【强制】线程池不允许使用 Executors 去创建,而是通过
ThreadPoolExecutor的方式,这样
的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明: Executors 返回的线程池对象的弊端如下:
  1) FixedThreadPool 和 SingleThreadPool :
    允许的请求队列长度为 Integer.MAX_VALUE ,可能会堆积大量的请求,从而导致 OOM 。
  2) CachedThreadPool 和 ScheduledThreadPool :
    允许的创建线程数量为 Integer.MAX_VALUE ,可能会创建大量的线程,从而导致 OOM 。

(三) ThreadPoolExecutor七个核心参数

1 public ThreadPoolExecutor(int corePoolSize,
2                           int maximumPoolSize,
3                           long keepAliveTime,
4                           TimeUnit unit,
5                           BlockingQueue<Runnable> workQueue,
6                           ThreadFactory threadFactory,
7                           RejectedExecutionHandler handler) 

1、corePoolSize

  核心池的大小。在创建了线程池之后,默认情况下,线程池中没有任何线程,而是等待有任务到来才创建线程去执行任务。默认情况下,在创建了线程池之后,线程池钟的线程数为0,当有任务到来后就会创建一个线程去执行任务

2、maximumPoolSize

  池中允许的最大线程数,这个参数表示了线程池中最多能创建的线程数量,当任务数量比corePoolSize大时,任务添加到workQueue,当workQueue满了,将继续创建线程以处理任务,maximumPoolSize表示的就是wordQueue满了,线程池中最多可以创建的线程数量

3、keepAliveTime

  只有当线程池中的线程数大于corePoolSize时,这个参数才会起作用。当线程数大于corePoolSize时,终止前多余的空闲线程等待新任务的最长时间

4、unit

  keepAliveTime时间单位

5、workQueue

  存储超过corePoolSize的线程,在这个队列中等待。

6、threadFactory

  执行程序创建新线程时使用的工厂

7、handler

  由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序

(四) 代码用例

 1 package com.test;
 2 
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.LinkedBlockingQueue;
 5 import java.util.concurrent.ThreadPoolExecutor;
 6 import java.util.concurrent.TimeUnit;
 7 
 8 /**
 9     author  wenbochang
10     public ThreadPoolExecutor(int corePoolSize,
11                               int maximumPoolSize,
12                               long keepAliveTime,
13                               TimeUnit unit,
14                               BlockingQueue<Runnable> workQueue) {
15         this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
16              Executors.defaultThreadFactory(), defaultHandler);
17     }
18  */
19 public class ThreadPoolTest {
20     public static void main(String[] args) {
21         
22         ExecutorService executorService = 
23                 new ThreadPoolExecutor(
24                 5, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024));
25         for (int i = 0; i < 10; i++) {
26             executorService.execute(new MyTask());
27         }
28         System.out.println(executorService);
29         executorService.shutdown();
30     }
31 }
32 
33 class MyTask implements Runnable{
34 
35     @Override
36     public void run() {
37         
38         System.out.println("Thread name : " + Thread.currentThread().getName());
39     }
40 }

大家可以调整下 corePoolSize   maximumPoolSize  workQueue 这三个参数的大小。

可以更加深刻理解这三个参数的意义。

我之前的确没有发现,Executors创建线程的坏处。但我在知乎看了一篇文章,里面说就是由于 Executors.newCachedThreadPool 无界队列,导致cpu飙升。所以大家还是好好的用ThreadPoolExecutor创建线程吧。

ps。我写文章是为了自己加深记忆,也为了和大家进行交流(我不保证100%为自己原创,因为在写文章的过程中,我也会找资料)。

如果不喜欢我写的文章,默默x掉就行,不要喷我,谢谢,共同进步

作者:wenbochang