Java中ThreadPoolExecutor的参数理解

一、使用Executors创建线程池

之前创建线程的时候都是用的Executors的newFixedThreadPool(),newSingleThreadExecutor(),newCachedThreadPool()这三个方法。当然Executors也是用不同的参数去new ThreadPoolExecutor

1. newFixedThreadPool()

创建线程数固定大小的线程池。 由于使用了LinkedBlockingQueue所以maximumPoolSize 没用,当corePoolSize满了之后就加入到LinkedBlockingQueue队列中。每当某个线程执行完成之后就从LinkedBlockingQueue队列中取一个。所以这个是创建固定大小的线程池。

 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
      this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

2.newSingleThreadPool()

创建线程数为1的线程池,由于使用了LinkedBlockingQueue所以maximumPoolSize 没用,corePoolSize为1表示线程数大小为1,满了就放入队列中,执行完了就从队列取一个。

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

3.newCachedThreadPool()

创建可缓冲的线程池。没有大小限制。由于corePoolSize为0所以任务会放入SynchronousQueue队列中,SynchronousQueue只能存放大小为1,所以会立刻新起线程,由于maxumumPoolSize为Integer.MAX_VALUE所以可以认为大小为2147483647。受内存大小限制。

 public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

二、使用ThreadPoolExecutor创建线程池

ThreadPoolExecutor的构造函数

  public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

参数:

    1、corePoolSize核心线程数大小,当线程数<corePoolSize ,会创建线程执行runnable

    2、maximumPoolSize 最大线程数, 当线程数 >= corePoolSize的时候,会把runnable放入workQueue中

    3、keepAliveTime  保持存活时间,当线程数大于corePoolSize的空闲线程能保持的最大时间。

    4、unit 时间单位

    5、workQueue 保存任务的阻塞队列

    6、threadFactory 创建线程的工厂

    7、handler 拒绝策略

任务执行顺序:

    1、当线程数小于corePoolSize时,创建线程执行任务。

    2、当线程数大于等于corePoolSize并且workQueue没有满时,放入workQueue中

    3、线程数大于等于corePoolSize并且当workQueue满时,新任务新建线程运行,线程总数要小于maximumPoolSize

    4、当线程总数等于maximumPoolSize并且workQueue满了的时候执行handler的rejectedExecution。也就是拒绝策略。

ThreadPoolExecutor默认有四个拒绝策略:

    1、ThreadPoolExecutor.AbortPolicy()   直接抛出异常RejectedExecutionException

    2、ThreadPoolExecutor.CallerRunsPolicy()    直接调用run方法并且阻塞执行

    3、ThreadPoolExecutor.DiscardPolicy()   直接丢弃后来的任务

    4、ThreadPoolExecutor.DiscardOldestPolicy()  丢弃在队列中队首的任务

当然可以自己继承RejectedExecutionHandler来写拒绝策略.

int corePoolSize = 1;
        int maximumPoolSize = 2;
        int keepAliveTime = 10;
//        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(5);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        //线程池和队列满了之后的处理方式
        //1.跑出异常
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        RejectedExecutionHandler handler2 = new ThreadPoolExecutor.CallerRunsPolicy();
        RejectedExecutionHandler handler3 = new ThreadPoolExecutor.DiscardPolicy();
        RejectedExecutionHandler handler4 = new ThreadPoolExecutor.DiscardOldestPolicy();

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, threadFactory, handler2);

        for (int j = 1; j < 15; j++) {
            threadPoolExecutor.execute(new Runnable() {

                public void run() {

                    try {
                        System.out.println(Thread.currentThread().getName());
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            });
        }

        System.out.println(threadPoolExecutor);

    }

文章转载自 开源中国社区[https://www.oschina.net]

时间: 2024-08-22 09:34:46

Java中ThreadPoolExecutor的参数理解的相关文章

浅谈Java中的可变参数_java

可变参数 可变参数就是一个方法可以接收任意多个参数!例如:fun().fun(1).fun(1,1).fun(1,1,1).你可能认为这是方法重载,但这不是重载,你想想重载能重载多少个方法,而fun()方法是可以传递任何个数的参数,你能重载这么多个方法么? 2.1 定义可变参数方法 public voidfun(int- arr) {} 上面方法fun()的参数类型为int-,其中"-"不是省略号,而是定义参数类型的方式.参数arr就是可变参数类型.你可以把上面代码理解为:public

游戏编程-java中的setBounds参数改变了没有什么变化

问题描述 java中的setBounds参数改变了没有什么变化 import java.awt.*;import java.awt.event.*;import javax.swing.*;import java.io.*;import javax.imageio.ImageIO;import java.awt.Image;class SFish1 extends JFrame{ JPanel panel = new JPanel(); Fish c; public SFish1() { add

请问java中‘封装技术’怎么理解,要通俗的

问题描述 请问java中'封装技术'怎么理解,要通俗的 解决方案 解决方案二:就是把属性和方法封装在一个类中解决方案三:就像手电筒,你只要装上电池和小灯泡,他就可以使用了,你看不到他内的线路,也不用知道他的原理,也就不能改变他的线路图了....解决方案四:封装,就是数据私有化,提供共有的方法去访问.!比如说:我现在18岁,这个年龄的属性私有,对外提供访问和修改我年龄的方式,但是这个修改因为是我自己提供的方法,所以修改的动作也是由我自己完成的,而非外界.!够通俗么.?解决方案五:引用1楼yiyan

对Java中传值调用的理解分析_java

本文实例分析了Java中的传值调用.分享给大家供大家参考.具体分析如下: Java以引用的方式操作对象实例 可以确认的是Java中操作对象的方式是以引用的方式操作对象.为了更深刻的了解这点我写了如下代码: 首先定义一个自定义类型 复制代码 代码如下: public class Person {            String name;            Person(String name){          this.name = name;      }  } 这里name默认是

谈谈Java中Volatile关键字的理解_java

volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以重获生机.volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情. 一.前言 JMM提供了volatile变量定义.final.synchronized块来保证可见性. 用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值.volatile很容

Java中线程安全问题个人理解

线程安全问题是一个比较高深的问题,是很多程序员比较难掌握的一个技术难点,如果一个程序员对线程掌握的很好的话,那么这个程序员的内功修炼的是相当的好. 在这里我主要说一下我对java中如何保证线程安全的一些个人见解,希望对各位有所帮助,那里有不对的地方敬请给位不吝赐教. 线程安全问题主要出现在访问临界资源的时候,就是访问同一个对象的时候,可能会出现无法挽回的损失,特别是在关于资金安全方面的时候,当然还有数据库事务方面的问题.他们很类似,都是要保证数据的原子性. 那么在java中如何保证线程安全呢?

Java中substring的参数及字符串的相等判断

字符串操作无疑在各种编程语言及平台上都是必不可少的,功能相通,但用法却存在微妙的区别,比如java中取子串及相等的判断,切入正题. 1. substring 常用的用法包括: (1)取索引为startidx之后(包括索引为startidx的字符)的字符串. 例:String strHello = "hello"; String strSub = strHello.substring(2); //得到"llo" (2)取起始索引为startidx之后(包括索引为sta

Java中支持可变参数详解_java

意思就是:参数的个数可以根据需要写,你可以写1个.2个.3个....他们都被保存到一个参数的数组中. 但是这些参有一些约束:他们必须是同类型的,比如都是String字符串类型. 同时,可变参数的函数中的参数的写法也有约束:比如,可变参数的数组必须写在参数的最后,否则程序不知道你的参数到底有多少个. 例子:输出可变参数中的参数值 public class VariableArgument { public static void main(String[] args) { printArgumen

java中zabbix常用参数与命令

  常用的参数: # /usr/local/iftop/sbin/iftop help //查看帮助命令 -i设定监测的网卡,如:# iftop -i eth1 -B 以bytes为单位显示流量(默认是bits),如:# iftop -B -n使host信息默认直接都显示IP,如:# iftop -n -N使端口信息默认直接都显示端口号,如: # iftop -N -F显示特定网段的进出流量,如# iftop -F 10.10.1.0/24或# iftop -F 10.10.1.0/255.25