博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[线程]线程池
阅读量:5907 次
发布时间:2019-06-19

本文共 4876 字,大约阅读时间需要 16 分钟。

 

一、概述

一个简单线程的创建和销毁如下代码,与进程进程相比,线程是一种轻量级的工具,但是轻量并不代表没有,它的创建和关闭依然需要花费时间,如果创建和销毁的时间还大于线程本身完成的工作,那就会得不偿失,甚至会造成Out of Memory。即使没有,大量的线程回收也会给GC带来巨大的压力。为了解决这样的问题,那么线程池应运而生。

new Thread(new Runnable() {					@Override			public void run() {				// TODO Auto-generated method stub				}					}).start();

二、什么是线程池

线程池和数据库连接池是类似的概念,在池中总有那么几个活跃的线程,当程序中线程时,从池中取出一个,用完后不直接关闭,而是放回池中。

三、JDK对线程池的支持

  • Executor框架提供了多种类型的线程池:
public static ExecutorService newFixedThreadPool(int nThreads) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue
()); }
  1. newFixedThreadPool() :返回一个固定线程数量的线程池,当一个任务来时,如果有空闲的线程,那么就立即执行,否则就将任务放到缓存队列。
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {        return new DelegatedScheduledExecutorService            (new ScheduledThreadPoolExecutor(1));    }
  1. newSingleThreadExecutor() :返回只有一个线程的线程池,如果有任务来,空闲就处理,否则放入缓存队列。
public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue
()); }
  1. newCachedThreadPool() :返回一个可根据实际情况调整线程数量的线程池,数量不确定,但是空闲的线程可以优先复用,当任务来时,若有空闲线程就复用,否则创建新的线程,使用完毕后返回线程池复用。
public static ExecutorService newSingleThreadExecutor() {        return new FinalizableDelegatedExecutorService            (new ThreadPoolExecutor(1, 1,                                    0L, TimeUnit.MILLISECONDS,                                    new LinkedBlockingQueue
())); }
  1. newSingleThreadScheduledExecutor(): 返回一个ScheduledExecutorService 对象,线程池大小为1,ScheduledExecutorService 可以给定时间执行某个任务,或者周期性的执行某个任务。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {        return new ScheduledThreadPoolExecutor(corePoolSize);    }
  1. newScheduledThreadPool(int corePoolSize): 也是返回一个ScheduledExecutorService对象,但是可以指定线程池中线程的数量。
  • 核心线程实现刨根问底:
    仔细看newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor 这三个线程池的构造函数,虽然它们分别实现不同功能的线程池,但是都是调用了ThreadPoolExecutor 来实现的。功能如此强大的ThreadPoolExecutor ,看看它的构造函数:
/**	 * 	 * @param corePoolSize          线程池中线程的数量	 * @param maximumPoolSize		最大线程数量	 * @param keepAliveTime			线程数超过指定的数量,多于线程的最大存活时间	 * @param unit					存活时间的单位	 * @param workQueue				任务队列,提交,但是还没有执行的任务	 * @param threadFactory			创建线程的工厂	 * @param handler				任务太多时,拒绝任务的策略	 */    public ThreadPoolExecutor(int corePoolSize,            int maximumPoolSize,            long keepAliveTime,            TimeUnit unit,            BlockingQueue
workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { //... 核心实现 }

ThreadPoolExecutor 的构造函数参数中,其他的都比较简单,详细看一下 workQueue (任务队列)和 handler ( 拒绝策略)

  1. workQueue :BlockingQueue<Runnable>接口的对象,实现有如下

    1. 直接提交的队列 (SynchronousQueue)
    2. 有界的任务队列 (ArrayBlockingQueue)
    3. 无界的任务队列 (LinkedBlockingQueue)
    4. 优先任务队列 (PriorityQueue)
  2. handler 拒绝策略 :JDK内置了四种拒绝策略如下:

    1. AbortPolicy:直接抛出异常,组织系统正常工作。
    2. CallerRunsPolicy: 只要线程池没有关闭,该策略直接在调用者的线程中,运行被丢弃的任务,虽然不会真的丢失任务,但是任务提交线程的性能会下降。
    3. DiscardOldestPolicy:该策略将丢弃最老的一个请求
    4. DiscardPolicy:直接丢弃无法处理的任务
      线程池拒绝策略
      如上图看到的,所有的拒绝策略都是 RejectedExecutionHandler 接口的实现,如果以上的策略无法满足生产环境的要求,也可以自定义拒绝策略。
  • 自定义扩展线程池
    对于既有线程池的扩展可以从两个方面,ThreadPoolFactory(创建线程的方法,以及设置一些线程的属性), 以及ThreadPoolExecutor的三个扩展方法:beforeExecute(Thread t, Runnable r)、afterExecute(Runnable r, Throwable t)、terminated()。

下面是一个例子:

public class ExtThreadPool {	public static void main(String[] args) throws InterruptedException {		ExecutorService es = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS,				new LinkedBlockingQueue
(), new ThreadFactory() { // 自定义线程创建的方法,可设置线程的相关属性 @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); System.out.println("创建线程" + t); return t; } }) { // 扩展线程池,增强线程执行之前 之后,以及结束的相关操作 @Override protected void beforeExecute(Thread t, Runnable r) { System.out.println(((MyTask) r).name + "执行之前"); } @Override protected void afterExecute(Runnable r, Throwable t) { System.out.println(((MyTask) r).name + "执行完毕"); } @Override protected void terminated() { System.out.println("线程退出!!!"); } }; for (int i = 0; i < 5; i++) { MyTask task = new MyTask("Task" + i); es.execute(task); // 特别注意,在线程池中尽量使用execute()方法提交任务,否则程序出错信息看不到、很痛苦 Thread.sleep(1000); } es.shutdown(); } // 静态内部类 public static class MyTask implements Runnable { public String name; public MyTask(String name) { this.name = name; } @Override public void run() { System.out.println("正在执行的线程" + Thread.currentThread().getId() + " " + Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }}

在这里插入图片描述

转载于:https://www.cnblogs.com/ytuan996/p/10573603.html

你可能感兴趣的文章
2017中国私募基金峰会第三批参会机构公布
查看>>
Oracle的sqlnet.ora文件配置
查看>>
子查询的另一种方式——映射
查看>>
【Django】 rest-framework和RestfulAPI的设计
查看>>
Python pass 语句
查看>>
Ubuntu镜像文件下载
查看>>
线程池的启动策略
查看>>
使用sql语句创建修改SQL Server标识列(即自动增长列)
查看>>
白鹭引擎 - 显示对象与 HelloWord ( 绘制了一个红蓝相间的 2 x 2 格子 )
查看>>
Data Binding Android - Type parameter T has incompatible upper bounds : ViewDataBinding and MainAct
查看>>
nuget.org 无法加载源 https://api.nuget.org/v3/index.json 的服务索引
查看>>
CentOS 7 搭建基于携程Apollo(阿波罗)配置中心单机模式
查看>>
PHP与Excel 笔记
查看>>
js使用正则表达式验证身份证格式
查看>>
捋一捋js面向对象的继承问题
查看>>
hbase分布式集群搭建
查看>>
ASP.NET Core 2.0 : 六. 举个例子来聊聊它的依赖注入
查看>>
桥接模式-pattern系列
查看>>
centos7环境安装ElasticSearch
查看>>
VidLoc: A Deep Spatio-Temporal Model for 6-DoF Video-Clip Relocalization
查看>>