java线程池学习

最近想研究下线程的使用,但是如果自己创建一个线程,太费系统性能 ,所以打算自己写个线程池

参考博客:https://www.cnblogs.com/dolphin0520/p/3932921.html

参考书籍:<<java并发编程的艺术>>

一 Java中的ThreadPoolExecutor类

 java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类,因此如果要透彻地了解Java中的线程池,必须先了解这个类。下面我们来看一下ThreadPoolExecutor类的具体实现源码。

  在ThreadPoolExecutor类中提供了四个构造方法:

public class ThreadPoolExecutor extends AbstractExecutorService {
    .....
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
        BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
    ...
}

从上面的代码可以得知,ThreadPoolExecutor继承了AbstractExecutorService类,并提供了四个构造器,事实上,通过观察每个构造器的源码具体实现,发现前面三个构造器都是调用的第四个构造器进行的初始化工作。

下面解释下一下构造器中各个参数的含义:

  • corePoolSize: (线程池的基本大小) 当提交一个任务到线程池时,线程池会创建一个线程来执行任务,如果线程池的有空闲线程但是数量小于 corePoolSize时,也会创建一个线程来执行,等到需要执行的任务数 大于线程池基本大小的时候就不会再创建, 如果调用了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有基本线程。
  • maximumPoolSize:(线程池最大数量):线程池允许创建的最大线程数,如果队列满了.并且已经创建的线程数量小于最大线程数,则线程池会创建新的线程执行任务.值得注意的是,如果使用了无界的任务队列这个参数就没有效果了
  • keepAliveTime:(线程活动保持时间) :表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,就是说线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;如果任务很多,并且每个任务执行的时间比较短时,可以调大时间,提高线程的利用率
  • TimeUnit:
TimeUnit.DAYS;               //
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒
  • workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:
    • ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按FIFO(先进先出)原则对元素进行排序。
    • LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
    • SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于Linked-BlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列

    • PriorityBlockingQueue:一个具有优先级的无限阻塞队列
  • RejectedExecutionHandler handler(饱和策略):表示当拒绝处理任务时的策略,有以下四种取值:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 
  • ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。使用开源框架guava提供的ThreadFactoryBuilder可以快速给线程池里的线程设置有意义的名字,代码如下

    new ThreadFactoryBuilder().setNameFormat("XX-task-%d").build();

  以上是线程池的基本概念

二 线程池内部原理实现

1.在前面我们多次提到了任务缓存队列,即workQueue,它用来存放等待执行的任务。

  workQueue的类型为BlockingQueue<Runnable>,通常可以取下面三种类型:

  1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;

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

  3)synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。

2.线程池的状态

runState

 // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

  如果调用了shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;

  如果调用了shutdownNow()方法,则线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;

  当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。

 3.线程池获取资源情况

  要清楚corePoolSize和maximumPoolSize的含义;

  其次,要知道Worker是用来起到什么作用的;

  要知道任务提交给线程池之后的处理策略,这里总结一下主要有4点:

  • 如果当前线程池中的线程数目小于corePoolSize,则每来一个任务,就会创建一个线程去执行这个任务;
  • 如果当前线程池中的线程数目>=corePoolSize,则每来一个任务,会尝试将其添加到任务缓存队列当中,若添加成功,则该任务会等待空闲线程将其取出去执行;若添加失败(一般来说是任务缓存队列已满),则会尝试创建新的线程去执行这个任务;
  • 如果当前线程池中的线程数目达到maximumPoolSize,则会采取任务拒绝策略进行处理;

  如果线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止,直至线程池中的线程数目不大于corePoolSize;如果允许为核心池中的线程设置存活时间,那么核心池中的线程空闲时间超过keepAliveTime,线程也会被终止。

4.线程池的关闭

ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown()和shutdownNow(),其中:

  • shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
  • shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务

线程池关闭的原理是遍历线程池中的工作先,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法停止

shutdownNow首先将线程池的状态设置为stop,然后尝试停止所有正在执行或者暂停任务的线程

shutdown只是将线程池的状态设置成shutdown状态,然后中断所有没有正在执行的任务的线程

  只要调用了这两个关闭方法中的任意一个,isShutdown方法就会返回true。当所有的任务
都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于应该调用哪
一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown方法来关闭
线程池,如果任务不一定要执行完,则可以调用shutdownNow方法

5.线程的提交

  execute()用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功

  submit()用户提交需要返回值的任务,线程池会返回一个future类型的对象,通过这个对象判断是否执行成功,future.get()方法 get方法会阻塞当前线程知道任务完成,,而是用get(long time,timeuitl unit )会阻塞一段时间后返回,这个时间有可能没有执行完任务

Future<Object> future = executor.submit(harReturnValuetask);
try {
Object s = future.get();
} catch (InterruptedException e) {
// 处理中断异常
} catch (ExecutionException e) {
// 处理无法执行任务异常
} finally {
// 关闭线程池
executor.shutdown();
}

三 使用实例

 /**
     * corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线
     * 程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任
     * 务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads()方法,
     * 线程池会提前创建并启动所有基本线程。
     */
    private static  int corePoolSize  =5;
    /**
     * (线程池最大数量):线程池允许创建的最大线程数。如果队列满了,并
     * 且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是,如
     * 果使用了无界的任务队列这个参数就没什么效果
     */

    private static  int maximumPoolSize  =10;

    /**
     * (线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以,
     * 如果任务很多,并且每个任务执行的时间比较短,可以调大时间,提高线程的利用率
     * @param args
     */
    private static long keepAliveTime =200;

    public static void main(String[] args) {


        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(5));

        for (int i = 0; i <20 ; i++) {

            executor.submit(new Mytask(i));
            System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
                    executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount());
        }
        executor.shutdown();
    }
}


class Mytask implements Runnable{

    private int a;

    public Mytask(int a) {
        this.a = a;
    }

    @Override
    public void run() {
        System.out.println(a+"任务执行");
        try {
            Thread.currentThread().sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(a+"执行完毕");
    }
/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=61838:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/lib/tools.jar:/Users/xuyuanfang/IdeaProjects/threaddemo/target/classes:/Users/xuyuanfang/apps/maven_jar/org/springframework/boot/spring-boot-starter-web/2.1.3.RELEASE/spring-boot-starter-web-2.1.3.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/boot/spring-boot-starter/2.1.3.RELEASE/spring-boot-starter-2.1.3.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/boot/spring-boot/2.1.3.RELEASE/spring-boot-2.1.3.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/boot/spring-boot-autoconfigure/2.1.3.RELEASE/spring-boot-autoconfigure-2.1.3.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/boot/spring-boot-starter-logging/2.1.3.RELEASE/spring-boot-starter-logging-2.1.3.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar:/Users/xuyuanfang/apps/maven_jar/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar:/Users/xuyuanfang/apps/maven_jar/org/apache/logging/log4j/log4j-to-slf4j/2.11.2/log4j-to-slf4j-2.11.2.jar:/Users/xuyuanfang/apps/maven_jar/org/apache/logging/log4j/log4j-api/2.11.2/log4j-api-2.11.2.jar:/Users/xuyuanfang/apps/maven_jar/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar:/Users/xuyuanfang/apps/maven_jar/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar:/Users/xuyuanfang/apps/maven_jar/org/yaml/snakeyaml/1.23/snakeyaml-1.23.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/boot/spring-boot-starter-json/2.1.3.RELEASE/spring-boot-starter-json-2.1.3.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/com/fasterxml/jackson/core/jackson-databind/2.9.8/jackson-databind-2.9.8.jar:/Users/xuyuanfang/apps/maven_jar/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0.jar:/Users/xuyuanfang/apps/maven_jar/com/fasterxml/jackson/core/jackson-core/2.9.8/jackson-core-2.9.8.jar:/Users/xuyuanfang/apps/maven_jar/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.9.8/jackson-datatype-jdk8-2.9.8.jar:/Users/xuyuanfang/apps/maven_jar/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.9.8/jackson-datatype-jsr310-2.9.8.jar:/Users/xuyuanfang/apps/maven_jar/com/fasterxml/jackson/module/jackson-module-parameter-names/2.9.8/jackson-module-parameter-names-2.9.8.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/boot/spring-boot-starter-tomcat/2.1.3.RELEASE/spring-boot-starter-tomcat-2.1.3.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/org/apache/tomcat/embed/tomcat-embed-core/9.0.16/tomcat-embed-core-9.0.16.jar:/Users/xuyuanfang/apps/maven_jar/org/apache/tomcat/embed/tomcat-embed-el/9.0.16/tomcat-embed-el-9.0.16.jar:/Users/xuyuanfang/apps/maven_jar/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.16/tomcat-embed-websocket-9.0.16.jar:/Users/xuyuanfang/apps/maven_jar/org/hibernate/validator/hibernate-validator/6.0.14.Final/hibernate-validator-6.0.14.Final.jar:/Users/xuyuanfang/apps/maven_jar/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar:/Users/xuyuanfang/apps/maven_jar/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final.jar:/Users/xuyuanfang/apps/maven_jar/com/fasterxml/classmate/1.4.0/classmate-1.4.0.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/spring-web/5.1.5.RELEASE/spring-web-5.1.5.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/spring-beans/5.1.5.RELEASE/spring-beans-5.1.5.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/spring-webmvc/5.1.5.RELEASE/spring-webmvc-5.1.5.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/spring-aop/5.1.5.RELEASE/spring-aop-5.1.5.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/spring-context/5.1.5.RELEASE/spring-context-5.1.5.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/spring-expression/5.1.5.RELEASE/spring-expression-5.1.5.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/org/projectlombok/lombok/1.18.6/lombok-1.18.6.jar:/Users/xuyuanfang/apps/maven_jar/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/spring-core/5.1.5.RELEASE/spring-core-5.1.5.RELEASE.jar:/Users/xuyuanfang/apps/maven_jar/org/springframework/spring-jcl/5.1.5.RELEASE/spring-jcl-5.1.5.RELEASE.jar com.xiaodao.threaddemo.thread.ExecutorsTest
0任务执行
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@e9e54c2 rejected from java.util.concurrent.ThreadPoolExecutor@65ab7765[Running, pool size = 10, active threads = 10, queued tasks = 5, completed tasks = 0]
线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
1任务执行
线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
2任务执行
线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
3任务执行
线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
4任务执行
线程池中线程数目:5,队列中等待执行的任务数目:1,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:3,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:4,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
线程池中线程数目:6,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
10任务执行
线程池中线程数目:7,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
线程池中线程数目:8,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
11任务执行
12任务执行
线程池中线程数目:9,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
13任务执行
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
线程池中线程数目:10,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
14任务执行
    at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
    at com.xiaodao.threaddemo.thread.ExecutorsTest.main(ExecutorsTest.java:41)
1执行完毕
4执行完毕
0执行完毕
2执行完毕
8任务执行
3执行完毕
9任务执行
7任务执行
6任务执行
13执行完毕
5任务执行
11执行完毕
14执行完毕
12执行完毕
10执行完毕
9执行完毕
5执行完毕
8执行完毕
7执行完毕
6执行完毕

Process finished with exit code 130 (interrupted by signal 2: SIGINT)
View Code

我们可以看到当执行线程大于corePoolSize 时就会将任务放入缓存队列中取,但是我们把任务数放大程序就会拒绝执行,并报错

当我们换一个饱和策略就不会报错,工作中.

    public static void main(String[] args) {


        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,
                maximumPoolSize, keepAliveTime, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(5),
                new ThreadPoolExecutor.CallerRunsPolicy());

        for (int i = 0; i <20 ; i++) {

            executor.submit(new Mytask(i));
            System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
                    executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount());
        }
        executor.shutdown();
    }

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

不过在java doc中,并不提倡我们直接使用ThreadPoolExecutor,而是使用Executors类中提供的几个静态方法来创建线程池

Executors.newCachedThreadPool();        //创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE
Executors.newSingleThreadExecutor();   //创建容量为1的缓冲池
Executors.newFixedThreadPool(int);    //创建固定容量大小的缓冲池

一下是这个三个方法的具体实现

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

从它们的具体实现来看,它们实际上也是调用了ThreadPoolExecutor,只不过参数都已配置好了。

  newFixedThreadPool创建的线程池corePoolSize和maximumPoolSize值是相等的,它使用的LinkedBlockingQueue;

  newSingleThreadExecutor将corePoolSize和maximumPoolSize都设置为1,也使用的LinkedBlockingQueue;

  newCachedThreadPool将corePoolSize设置为0,将maximumPoolSize设置为Integer.MAX_VALUE,使用的SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程。

  实际中,如果Executors提供的三个静态方法能满足要求,就尽量使用它提供的三个方法,因为自己去手动配置ThreadPoolExecutor的参数有点麻烦,要根据实际任务的类型和数量来进行配置。

  另外,如果ThreadPoolExecutor达不到要求,可以自己继承ThreadPoolExecutor类进行重写。

 四 配置线程池的大小

  要想合理的配置线程池,首先要分析任务的特性,可以重以下几个点击来分析:

  •   任务的性质:CPU密集型任务,IO密集型任务,和混合型任务
  • 任务的优先级:高 中和低
  • 任务的执行时间:长 中和短
  • 任务的依赖性:是否依赖其他资源,如,数据连接,调用别的系统接口

CPU密集型任务尽可能配置小的线程,如配置Ncpu+1个线程的线程池

IO密集型任务线程并不是一直在执行任务:应该配置更多的线程,如 2* ncpu

可以通过 Runtime.getRuntime().availableProcessors()获取当前设备的cup个数

依赖数据库连接池的任务,因为线程提交SQL后需要等待数据库返回结果,等待的时间越长,则CPU空闲时间就越长,那么线程数应该设置得越大,这样才能更好地利用CPU

在spring中使用线程池

目前使用spring 中的线程池有点问题.自定义的线程池倒是可以使用,此处贴出代码

@Configuration
public class TheadPoolTask {
    /**
     * 获取线程池
     *
     * @return
     */
    @Bean
    public ThreadPoolExecutor threadPoolTaskExecutor(){

        ThreadPoolExecutor executor = new ThreadPoolExecutor(12,
                16, 12, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(5),
                new ThreadPoolExecutor.CallerRunsPolicy());

        return   executor;
    }
}

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = {"/spring-context.xml","/spring-context-jedis.xml","/spring-context-shiro.xml"})
public class ThreadTest {

    @Resource(name = "threadPoolTaskExecutor")
    private ThreadPoolExecutor taskExecutor;

    public static void main(String[] args) {
        System.out.println(Runtime.getRuntime().availableProcessors());
    }


    @Test
    public  void test01(){
        try {
        for (int i = 0; i <25 ; i++) {

        taskExecutor.submit(new Test01(i));
            System.out.println("线程池中线程数目:"+taskExecutor.getPoolSize()+",队列中等待执行的任务数目:"+
                    taskExecutor.getQueue().size()+",已执行玩别的任务数目:"+taskExecutor.getCompletedTaskCount());
        }
        CountDownLatch c = new CountDownLatch(1);

            c.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


class Test01 implements Runnable{

    private int a;

    public Test01(int a) {
        this.a = a;
    }

    @Override
    public void run() {
        try {
            System.out.println("线程开始"+ Thread.currentThread().getName()+"------"+a);
            Thread.sleep(5000);
            System.out.println("线程结束 "+ Thread.currentThread().getName()+"------"+a);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}
原文地址:https://www.cnblogs.com/bj-xiaodao/p/10622613.html