1. ThreadPoolExecutor的一个常用的构造方法

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)

参数说明:

-corePoolSize       线程池中所保存的核心线程数。线程池启动后默认是空的,只有任务来临时才会创建线程以处理请求。prestartAllCoreThreads方法可以在线程池启动后即启动所有核心线程以等待任务。

-maximumPoolSize  线程池允许创建的最大线程数。当workQueue使用无界队列时(如:LinkedBlockingQueue),则此参数无效。

-keepAliveTime      当前线程池线程总数大于核心线程数时,终止多余的空闲线程的时间。

-unit          keepAliveTime参数的时间单位。

-workQueue       工作队列,如果当前线程池达到核心线程数时(corePoolSize),且当前所有线程都处于活动状态,则将新加入的任务放到此队列中。下面仅列几个常用的:

  • ArrayBlockingQueue:  基于数组结构的有界队列,此队列按FIFO原则对任务进行排序。如果队列满了还有任务进来,则调用拒绝策略。
  • LinkedBlockingQueue:  基于链表结构的无界队列,此队列按FIFO原则对任务进行排序。因为它是无界的,根本不会满,所以采用此队列后线程池将忽略拒绝策略(handler)参数;同时还将忽略最大线程数(maximumPoolSize)等参数。
  • SynchronousQueue:   直接将任务提交给线程而不是将它加入到队列,实际上此队列是空的。每个插入的操作必须等到另一个调用移除的操作;如果新任务来了线程池没有任何可用线程处理的话,则调用拒绝策略。其实要是把maximumPoolSize设置成无界(Integer.MAX_VALUE)的,加上SynchronousQueue队列,就等同于Executors.newCachedThreadPool()。
  • PriorityBlockingQueue: 具有优先级的队列的有界队列,可以自定义优先级;默认是按自然排序,可能很多场合并不合适。

-handler          拒绝策略,当线程池与workQueue队列都满了的情况下,对新加任务采取的策略。

  • AbortPolicy:           拒绝任务,抛出RejectedExecutionException异常。默认值。
  • CallerRunsPolicy:   A handler for rejected tasks that runs the rejected task directly in the calling thread of the execute method, unless the executor has been shut down, in which case the task is discarded(没太弄懂意思,看不太懂,程序模拟半天也没得出啥结论。)
  • DiscardOldestPolicy:  如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)。这样的结果是最后加入的任务反而有可能被执行到,先前加入的都被抛弃了。
  • DiscardPolicy:      加不进的任务都被抛弃了,同时没有异常抛出。

2. 详解及示范

  1. 一个任务进来(Runnable)时,如果核心线程数(corePoolSize)未达到,则直接创建线程处理该任务;如果核心线程数已经达到则该任务进入工作队列(workQueue)。如果工作队列满了(只能是有界队列),则检查最大线程数(maximumPoolSize)是否达到,如果没达到则创建线程处理任务(FIFO);如果最大线程数据也达到了,则调用拒绝策略(handler)。
  2. 如果workQueue使用LinkedBlockingQueue队列,因为它是无界的,队列永远不会满,所以maximumPoolSize参数是没有意义的,同样keepAliveTime、unit、handler三个参数都无意义。
  3. 如果workQueue使用ArrayBlockingQueue队列,那么小心,因为此队列是有界的,必须小心处理拒绝策略。你看人家Executors类,压根就不使用ArrayBlockingQueue队列。
  4. 正常情况下,如果使用Executors静态工厂生成的几种常用线程池能够满足要求,建议就用它们吧。自己控制所有细节挺不容易的。
package com.clzhang.sample.thread;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; public class ThreadPoolTest3 {
static class MyThread implements Runnable {
private String name; public MyThread(String name) {
this.name = name;
} @Override
public void run() {
// 做点事情
try {
Thread.sleep(1000); System.out.println(name + " finished job!") ;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
// 创建线程池,为了更好的明白运行流程,增加了一些额外的代码
// BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(2);
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
// BlockingQueue<Runnable> queue = new PriorityBlockingQueue<Runnable>();
// BlockingQueue<Runnable> queue = new SynchronousQueue<Runnable>();


// AbortPolicy/CallerRunsPolicy/DiscardOldestPolicy/DiscardPolicy
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 5, TimeUnit.SECONDS,
queue, new ThreadPoolExecutor.AbortPolicy()); // 向线程池里面扔任务
for (int i = 0; i < 10; i++) {
System.out.println("当前线程池大小[" + threadPool.getPoolSize() + "],当前队列大小[" + queue.size() + "]"); threadPool.execute(new MyThread("Thread" + i));
}
// 关闭线程池
threadPool.shutdown();
}
}

输出(采用LinkedBlockingQueue队列):

当前线程池大小[0],当前队列大小[0]
当前线程池大小[1],当前队列大小[0]
当前线程池大小[2],当前队列大小[0]
当前线程池大小[2],当前队列大小[1]
当前线程池大小[2],当前队列大小[2]
当前线程池大小[2],当前队列大小[3]
当前线程池大小[2],当前队列大小[4]
当前线程池大小[2],当前队列大小[5]
当前线程池大小[2],当前队列大小[6]
当前线程池大小[2],当前队列大小[7]
Thread1 finished job!
Thread0 finished job!
Thread3 finished job!
Thread2 finished job!
Thread4 finished job!
Thread5 finished job!
Thread6 finished job!
Thread7 finished job!
Thread8 finished job!
Thread9 finished job!

3. 回头看看Executors静态工厂方法生成线程池的源代码

Executors.newSingleThreadExecutor()

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

Executors.newFixedThreadPool()

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

Executors.newCachedThreadPool()

    public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}

通过上述代码可以发现,用Executors静态工厂生成的几种常用线程池,都可以向里面插入n多任务:要么workQueue是无界的,要么maximumPoolSize是无界的。

Java:多线程,线程池,ThreadPoolExecutor详解的更多相关文章

  1. Java—线程池ThreadPoolExecutor详解

    引导 要求:线程资源必须通过线程池提供,不允许在应用自行显式创建线程: 说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题.如果不使用线程池,有可能造成系统 ...

  2. Java多线程-线程池ThreadPoolExecutor构造方法和规则

    为什么用线程池 原文地址 http://blog.csdn.net/qq_25806863/article/details/71126867 有时候,系统需要处理非常多的执行时间很短的请求,如果每一个 ...

  3. java多线程——线程池源码分析(一)

    本文首发于cdream的个人博客,点击获得更好的阅读体验! 欢迎转载,转载请注明出处. 通常应用多线程技术时,我们并不会直接创建一个线程,因为系统启动一个新线程的成本是比较高的,涉及与操作系统的交互, ...

  4. Executor线程池原理详解

    线程池 线程池的目的就是减少多线程创建的开销,减少资源的消耗,让系统更加的稳定.在web开发中,服务器会为了一个请求分配一个线程来处理,如果每次请求都创建一个线程,请求结束就销毁这个线程.那么在高并发 ...

  5. Java多线程之ThreadPoolExecutor详解使用

    1.概述 我将讲解JAVA原生线程池的基本使用,并由此延伸出JAVA中和线程管理相关的类结构体系,然后我们详细描述JAVA原生线程池的结构和工作方式 2.为什么要使用线程池 前文我们已经讲到,线程是一 ...

  6. Java多线程-----线程池详解

    1. 线程池的实现原理 提交一个任务到线程池中,线程池的处理流程如下: 判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务.如果 ...

  7. JAVA线程池原理详解二

    Executor框架的两级调度模型 在HotSpot VM的模型中,JAVA线程被一对一映射为本地操作系统线程.JAVA线程启动时会创建一个本地操作系统线程,当JAVA线程终止时,对应的操作系统线程也 ...

  8. 用 ThreadPoolExecutor/ThreadPoolTaskExecutor 线程池技术提高系统吞吐量(附带线程池参数详解和使用注意事项)

    1.概述 在Java中,我们一般通过集成Thread类和实现Runnnable接口,调用线程的start()方法实现线程的启动.但如果并发的数量很多,而且每个线程都是执行很短的时间便结束了,那样频繁的 ...

  9. JAVA线程池原理详解一

    线程池的优点 1.线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用. 2.可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃. 线 ...

  10. JAVA线程池原理详解(1)

    线程池的优点 1.线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用. 2.可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃. 线 ...

随机推荐

  1. Java+FlashWavRecorder实现网页录音并上传

    [注意] 最新版本号请看这里:http://uikoo9.com/blog/detail/java-flashwavrecorder [前言] 肯定有需求要网页录音,并且要上传.这奇葩需求. 然后找到 ...

  2. 在 Ubuntu 12.04 上通过源码安装 Open vSwitch (OVS)

    安装 Ubuntu 12.04, 而且更新系统 apt-getupdate; apt-getupgrade; 安装所需的package apt-get install automake autocon ...

  3. 如何用代码组织多个Storyboard(故事板)

    1. 新建一个Storyboard取名为OtherStoryboard.storyboard 2. 使用下面代码加载 UIStoryboard *newStoryboard = [UIStoryboa ...

  4. VMware Workstation 12下载安装与激活图文教程

    一.简介: VMware Workstation 12专门为Win10的安装和使用做了优化,支持DX10.4K高分辨率显示屏.OpenGL 3.3.7.1声道,以及各种新硬件和新技术.从vm11版本开 ...

  5. 局域网连接打印机(Win10)

    局域网支持交换机和WIFI环境下进行连接(要求连上打印机的电脑已开启) 1.首先打开控制面板 2.硬件和声音 3.高级打印机设置 4.找到要连接的打印机,通过浏览(R) 添加局域网某台机器上的打印机, ...

  6. eclipse导入web项目各种错误

    1.JavaWeb:报错信息The superclass "javax.servlet.http.HttpServlet" was not found on the Java Bu ...

  7. JSP实现数据传递(web基础学习笔记三)

    get和post的区别: JSP内置对象: 1)out内置对象:out内置对象是在JSP开发过程中使用得最为频繁的对象,然而其使用起来也是最简单的.out对象用于向客户端浏览器输出数         ...

  8. webpack 安装以及使用

    1.安装webpack 全局安装代码: npm install -g webpack 2.项目中使用webpack (1)进入项目目录 cd C:\Users\dell\Documents\HBuil ...

  9. 简单的Stack

    自己实现的简单的Stack.没有查空满.用于算法考试 #include<iostream> using namespace std; const int MAX = 100; struct ...

  10. 感谢CSDN赠送的图书和杂志(5月份)

    互联网的精神就是开放.就是分享.在分享的同一时候.我们也会收获到意外的回报. 近期.因为我在5月份发表了14篇博文,因此CSDN赠送了一本图书<软件系统架构>(本人自己选的)和一本< ...