一、线程池的创建

我们可以通过ThreadPoolExecutor来创建一个线程池。

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

创建一个线程池需要输入几个参数:

  • corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。
  • runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。 可以选择以下几个阻塞队列。
    • ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
    • LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
    • SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工Executors.newCachedThreadPool使用了这个队列。
    • PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
  • maximumPoolSize(线程池最大大小):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。
  • ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。
  • RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。
    • AbortPolicy:直接抛出异常。
    • CallerRunsPolicy:只用调用者所在线程来运行任务。
    • DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
    • DiscardPolicy:不处理,丢弃掉。 当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
  • keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。
  • TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

二、特定功能的线程池

Executors提供了一些静态工厂方法,可以方便创建ThreadPoolExecutor

1、 Executors.newFixedThreadPool(int nThreads)

创建固定大小(nThreads,大小不能超过int的最大值)的线程池

        //线程数量
int nThreads = 20;
//创建executor 服务
ExecutorService executor = Executors.newFixedThreadPool(nThreads) ;

重载后的版本,需要多传入实现了ThreadFactory接口的对象。

ExecutorService executor = Executors. newFixedThreadPool(nThreads,threadFactory);

说明:创建固定大小(nThreads,大小不能超过int的最大值)的线程池,缓冲任务的队列为LinkedBlockingQueue,大小为整型的最大数,当使用此线程池时,在同执行的任务数量超过传入的线程池大小值后,将会放入LinkedBlockingQueue,在LinkedBlockingQueue中的任务需要等待线程空闲后再执行,如果放入LinkedBlockingQueue中的任务超过整型的最大数时,抛出RejectedExecutionException。

2、Executors.newSingleThreadExecutor()

创建大小为1的固定线程池。

ExecutorService executor = Executors.newSingleThreadExecutor();

重载后的版本,需要多传入实现了ThreadFactory接口的对象。

ExecutorService executor = Executors. newSingleThreadScheduledExecutor(ThreadFactory threadFactory)

说明:创建大小为1的固定线程池,同时执行任务(task)的只有一个,其它的(任务)task都放在LinkedBlockingQueue中排队等待执行。

3、Executors.newCachedThreadPool();

创建corePoolSize为0,最大线程数为整型的最大数,线程keepAliveTime为1分钟,缓存任务的队列为SynchronousQueue的线程池。

ExecutorService executor = Executors.newCachedThreadPool();

当然也可以以下面的方式创建,重载后的版本,需要多传入实现了ThreadFactory接口的对象。

ExecutorService executor = Executors.newCachedThreadPool(ThreadFactory threadFactory) ;

说明:使用时,放入线程池的task任务会复用线程或启动新线程来执行,注意事项:启动的线程数如果超过整型最大值后会抛出RejectedExecutionException异常,启动后的线程存活时间为一分钟。

4、Executors.newScheduledThreadPool(int corePoolSize):

创建corePoolSize大小的线程池。

//线程数量
int corePoolSize= 20;
//创建executor 服务
ExecutorService executor = Executors.newScheduledThreadPool(corePoolSize);

重载后的版本,需要多传入实现了ThreadFactory接口的对象。

ExecutorService executor = Executors.newScheduledThreadPool(corePoolSize, threadFactory);

说明:线程keepAliveTime为0,缓存任务的队列为DelayedWorkQueue,注意不要超过整型的最大值。

三、常用方法介绍

1、submit

 <T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

将一个线程加入线程池并执行,同时可以返回一个Future对象,Future.get() 方法可以更方便的获得异常信息

2、execute

public void execute(Runnable command)

execute方法的作用与submit相同,只是没有返回值

3、invokeAll

 <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)

invokeAll方法的参数就是一组任务,并返回一组Future。这2个集合具有相同的结构。invokeAll会按照任务集合中的顺序将所有的Future添加到返回的集合中。只有当所有的任务都执行完毕时,或者调用线程被中断,又或者超出指定时限时,invokeAll方法才会返回。当invokeAll返回之后每个任务要么返回,要么取消,此时客户端可以调用get/isCancelled来判断具体是什么情况。

4、invokeAny

<T> T invokeAny(Collection<? extends Callable<T>> tasks)
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)

执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。

java基础系列——线程池的更多相关文章

  1. Java多线程系列——线程池简介

    什么是线程池? 为了避免系统频繁地创建和销毁线程,我们可以让创建的线程进行复用.用线程时从线程池中获取,用完以后不销毁线程,而是归还给线程池. JDK 对线程池的支持 为了更好的控制多线程,JDK 提 ...

  2. Java基础教程——线程池

    启动新线程,需要和操作系统进行交互,成本比较高. 使用线程池可以提高性能-- 线程池会提前创建大量的空闲线程,随时待命执行线程任务.在执行完了一个任务之后,线程会回到空闲状态,等待执行下一个任务.(这 ...

  3. java基础-多线程线程池

    线程池 * 程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互.而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池.线程池里的每一个线程代 ...

  4. Java多线程系列——线程池原理之 ThreadPoolExecutor

    ThreadPoolExecutor 简介 ThreadPoolExecutor 是线程池类. 通俗的讲,它是一个存放一定数量线程的线程集合.线程池允许多个线程同时运行,同时运行的线程数量就是这个线程 ...

  5. Java 基础系列合集

    Java基础知识你知道多少? Java特性 Java三大特性:封装,继承,多态 Java 抽象类与接口 Java 浅拷贝和深拷贝 Java static和final Java 内部类.静态内部类.匿名 ...

  6. 夯实Java基础系列3:一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!

    目录 目录 string基础 Java String 类 创建字符串 StringDemo.java 文件代码: String基本用法 创建String对象的常用方法 String中常用的方法,用法如 ...

  7. 夯实Java基础系列4:一文了解final关键字的特性、使用方法,以及实现原理

    目录 final使用 final变量 final修饰基本数据类型变量和引用 final类 final关键字的知识点 final关键字的最佳实践 final的用法 关于空白final final内存分配 ...

  8. 夯实Java基础系列11:深入理解Java中的回调机制

    目录 模块间的调用 多线程中的"回调" Java回调机制实战 实例一 : 同步调用 实例二:由浅入深 实例三:Tom做题 参考文章 微信公众号 Java技术江湖 个人公众号:黄小斜 ...

  9. Java基础系列2:深入理解String类

    Java基础系列2:深入理解String类 String是Java中最为常用的数据类型之一,也是面试中比较常被问到的基础知识点,本篇就聊聊Java中的String.主要包括如下的五个内容: Strin ...

随机推荐

  1. javascritp第十课:面向对象

    js中的函数就是对象,对象就是函数,当js中需要使用面向对象,使用js闭包模拟面向对象,当函数作为对象使用时,每个单词首字母都大写 var obj=new object();  //js中默认就是ob ...

  2. app被Rejected 的各种原因翻译(转)

    原文:http://www.cnblogs.com/sell/archive/2013/02/16/2913341.html 1. Terms and conditions(法律与条款) 1.1 As ...

  3. iOS动画技术笔记

    概述 在IOS开发中,实现动画操作的地方有很多,典型的是在视图控制器的segue操作时.在同一个视图控制器类中,加载切换不同的视图时,也需要动画效果,还有一些视图对象有动画效果会更好. 插一句,在IO ...

  4. ASP.NET MVC 学习之路-2

    本文在于巩固基础 为了方便理解MVC框架,我们先创建空的ASP.NET MVC模板 下面是创建后的项目结构 每个文件或者文件夹的作用 App_Data 应用程序数据--- 顾名思义是放置文件或者数据库 ...

  5. iOS进阶:Objective-C runtime(一)

    第一次看到runtime时,觉得太高大上,动态获取方法.属性等简直厉害的不要不要的.在经过查找资料+实践后,发现runtime并没有想象中那么复杂,接下来对runtime进行基本的介绍. 要使用运行时 ...

  6. java 线程之间通信以及notify与notifyAll区别。

    jvm多个线程间的通信是通过 线程的锁.条件语句.以及wait().notify()/notifyAll组成. 下面来实现一个启用多个线程来循环的输出两个不同的语句. package com.app. ...

  7. Programming C#.Classes and Objects.成员方法

    this关键字指向类的当前实例,this指针是类中所有非静态方法的隐藏指针,每个方法都能通过this指针指向对象的其他方法和成员变量. 因为对一个类来说,它的成员函数(方法)只有一份,所有的实例对象共 ...

  8. 1.js编程风格。 --- 编写可维护的javascript

    1. 使用4个空格字符作为一个缩进层级. 2. 不省略分号. ---> 自动插入分号机制非常复杂,且难于记忆. 3. 行的长度限定于80个字符. 4. 通常在运算符换行之后,下一行会增加两个层级 ...

  9. 终于解决“Git Windows客户端保存用户名与密码”的问题

    这就是正确答案,我们已经验证过了,下面详细描述一下解决方法: 1. 在Windows中添加一个HOME环境变量,值为%USERPROFILE%,如下图: 2. 在“开始>运行”中打开%Home% ...

  10. 微博发布效果jq版

    大家都看过新浪微博的发状态功能,我模拟了一下类似的效果,包括发布时间,删除效果等.代码如下: <!DOCTYPE HTML> <html> <head> <m ...