Java并发编程(您不知道的线程池操作)

这几篇博客,一直在谈线程,设想一下这个场景,如果并发的线程很多,然而每个线程如果执行的时间很多的话,这样的话,就会大量的降低系统的效率。这时候就可以采用线程池的操作,来缓存我们并发操作的线程。

而对于java中的线程池,大家需要理解好ThreadPoolExecutor、AbstractExecutorService、ExecutorService和Executor这几个类之间的关系即可。

通过看上面的这个关系图,可以知道,最核心的一个类是ThreadPoolExecutor,我们下面来具体的看一下这个类的操作。

ThreadPoolExecutor类提供了四个构造函数,如下所示

<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;"><span style="font-family:Comic Sans MS;font-size:18px;">public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
			long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
		this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
				Executors.defaultThreadFactory(), defaultHandler);
	}

	public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
			long keepAliveTime, TimeUnit unit,
			BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
		this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
				threadFactory, defaultHandler);
	}

	public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
			long keepAliveTime, TimeUnit unit,
			BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
		this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
				Executors.defaultThreadFactory(), handler);
	}

	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;
	}</span></span></span>

下面来分析下这四个构造函数中每个参数的具体意义,其实主要是一些初始化的操作

corePoolSize:表明这个线程池的大小

     maximumPoolSize:表明这个线程池中,最多可以容纳多少个线程执行

     TimeUnit:线程存活的时间单位,有秒、小时、分钟等

     keepAliveTime:用来表示一个线程多长时间不执行任务后,就被废弃掉

     workQueue:阻塞队列,表示如何线程多余线程池的话,用来存储等待执行的任务,具体值如下


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

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

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

 threadFactory:一个线程工厂,用来创建线程

     handler:用来表示拒绝执行任务的策略。

下面通过举个例子来理解上述的表示参数。

假如有一个工厂,工厂里面有10个工人,每个工人同时只能做一件任务。 因此只要当10个工人中有工人是空闲的,来了任务就分配给空闲的工人做;当10
个工人都有任务在做时,如果还来了任务,就把任务进行排队等待;如果说新任务数目增长的速度远远大于工人做任务的速度,那么此时工厂主管可能会想补救措
施,比如重新招4个临时工人进来;然后就将任务也分配给这4个临时工人做;如果说着14个工人做任务的速度还是不够,此时工厂主管可能就要考虑不再接收新
的任务或者抛弃前面的一些任务了。当这14个工人当中有人空闲时,而新任务增长的速度又比较缓慢,工厂主管可能就考虑辞掉4个临时工了,只保持原来的10
个工人,毕竟请额外的工人是要花钱的。

这个例子中的corePoolSize就是10,而maximumPoolSize就是14(10+4)。

也就是说corePoolSize就是线程池大小,maximumPoolSize在我看来是线程池的一种补救措施,即任务量突然过大时的一种补救措施。

下面通过一个例子来了解上述的构造函数。

<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;"><span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;font-size:18px;">package com.test;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThreadPool {  

    public static void main(String[] args) {  

    	//创建一个线程池
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 6, 5,TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());  

        //通过循环来开启20个任务操作
         for (int i = 1; i <= 20; i++) {   

             threadPool.execute(new ThreadPoolTask());  

        }
    }
}

//创建 ThreadPoolTask类:

 class ThreadPoolTask implements Runnable {
    public void run() {
        try {
            System.out.println("开始执行任务:" + Thread.currentThread().getName());
            Thread.sleep(100);
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }  

}</span></span></span></span>

上面就是开启20个任务,来让线程池处理,如果线程池满了的话,就会放入到阻塞对列中进行等待操作

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

Executors.newCachedThreadPool();        //创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE

    Executors.newSingleThreadExecutor();   //创建容量为1的缓冲池
    Executors.newFixedThreadPool(int);    //创建固定容量大小的缓冲池


     下面是这三个静态方法的具体实现;

<span style="font-family:Comic Sans MS;font-size:18px;"><span style="font-family:Comic Sans MS;"><span style="font-family:Comic Sans MS;font-size:18px;">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>());

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

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

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

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

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

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

     参考资料:
       http://www.cnblogs.com/dolphin0520/p/3932921.html
      http://blog.csdn.net/hejingyuan6/article/details/47058189

Java并发编程(您不知道的线程池操作)的更多相关文章

  1. Java并发编程(您不知道的线程池操作), 最受欢迎的 8 位 Java 大师,Java并发包中的同步队列SynchronousQueue实现原理

    Java_并发编程培训 java并发程序设计教程 JUC Exchanger 一.概述 Exchanger 可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchan ...

  2. Java 并发编程——Executor框架和线程池原理

    Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...

  3. [Java并发编程(二)] 线程池 FixedThreadPool、CachedThreadPool、ForkJoinPool?为后台任务选择合适的 Java executors

    [Java并发编程(二)] 线程池 FixedThreadPool.CachedThreadPool.ForkJoinPool?为后台任务选择合适的 Java executors ... 摘要 Jav ...

  4. [Java并发编程(一)] 线程池 FixedThreadPool vs CachedThreadPool ...

    [Java并发编程(一)] 线程池 FixedThreadPool vs CachedThreadPool ... 摘要 介绍 Java 并发包里的几个主要 ExecutorService . 正文 ...

  5. Java 并发编程——Executor框架和线程池原理

    Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...

  6. Java并发编程之深入理解线程池原理及实现

    Java线程池在实际的应用开发中十分广泛.虽然Java1.5之后在JUC包中提供了内置线程池可以拿来就用,但是这之前仍有许多老的应用和系统是需要程序员自己开发的.因此,基于线程池的需求背景.技术要求了 ...

  7. Java并发编程、多线程、线程池…

    <实战java高并发程序设计>源码整理https://github.com/petercao/concurrent-programming/blob/master/README.md Ja ...

  8. Java并发编程(08):Executor线程池框架

    本文源码:GitHub·点这里 || GitEE·点这里 一.Executor框架简介 1.基础简介 Executor系统中,将线程任务提交和任务执行进行了解耦的设计,Executor有各种功能强大的 ...

  9. Java并发编程(十一)线程池的使用

    1.new Thread的弊端如下: a. 每次new Thread新建对象性能差. b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom. c. 缺乏更多 ...

随机推荐

  1. Python金融应用编程(数据分析、定价与量化投资)

    近年来,金融领域的量化分析越来越受到理论界与实务界的重视,量化分析的技术也取得了较大的进展,成为备受关注的一个热点领域.所谓金融量化,就是将金融分析理论与计算机编程技术相结合,更为有效的利用现代计算技 ...

  2. HTML5,微信开发原码社区

    HTML5开发助手,快速查看HTML及javascript接口文档 http://www.9miao.com/thread-60966-1-1.html 简洁的手机wap公司产品展示网站模板下载htm ...

  3. ExtJs4 笔记(11) Ext.ListView、Ext.view.View 数据视图

    本篇介绍两个用来展示数据的容器控件,分别是Ext.ListView和Ext.view.View.Ext.ListView就是大名鼎鼎的Ext GridPanel的前身,不过现在的Ext4已经将它整合到 ...

  4. JS-JavaScript学习笔记(一)

    javaScript 1.文档的输出:document.write() 可输出字符,表达式,html标签.函数 2.不论什么类型和字符串相加,都会被转换成字符串类型. 比如:var i=5; var ...

  5. 9月mob(ShareSDK)活动预告,这个秋天非常热

    9月秋天来临,广州的天气依旧非常热,广州的活动氛围更热~ 先有GMGC B2B对接会在广州创新谷,再有上方网TFC全球移动游戏开发人员大会来袭,游戏圈的火越烧越旺,成都GMGDC全球移动游戏开发人员大 ...

  6. html中加入超链接方式的汇总

    在CSS样式中,对超链接的样式有以下几种定义(1)设置链接未被访问时的样式,具体写法如下:a:link{font-size:10px;... }(2)设置链接在鼠标经过时的样式,具体写法如下:a:ho ...

  7. 不是技术牛人,如何拿到国内IT巨头的Offer(转)

    不久前,byvoid面阿里星计划的面试结果截图泄漏,引起无数IT屌丝的羡慕敬仰.看看这些牛人,NOI金牌,开源社区名人,三年级开始写Basic…在跪拜之余我们不禁要想,和这些牛人比,作为绝大部分技术屌 ...

  8. If-Modified-Since页面是否更新

    第一次先请求某个网页,抓取到本地,假设文件名为 a.html.这时文件系统有个文件的修改时间. 第二次访问网页,如果发现本地已经有了 a.html,则向服务器发送一个 If-Modified-Sinc ...

  9. spring开发基础

    Spring是一个开源框架,它由Rod Johnson创建.它是为了解决企业应用开发的复杂性而创建的.Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情.然而,Spring的用途 ...

  10. VMware Workstation(虚拟机软件) V10.0 简体中文版可以安装了

    在虚拟机软件中VMware Workstation算是一款非常强大较稳定的软件了,今天 VMware Workstation 10.0正式发布了,最让人欣喜的是该版本终于有了简体中 文版了,从现在开始 ...