线程池ThreadPoolExecutor类使用详解

线程池解决了2个不同的问题

1.提升了性能:通常是在执行大量的执行任务时,减少了每个线程的调用开销,并且它们提供了一种限制和资源管理(包括线程)的方法,从而提升了性能。

2.统计信息:每个TheardPoolExecutor保持一些基本的统计信息,例如完成的任务数量。

Executors.newCachedThreadPool(无界线程池,自动线程回收);
Executors.newFixedThreadPool(固定大小的线程池);
Executors.newSingleThreadExecutor(后台单一线程);

而线程池不允许用Executors去创建,而需要通过ThreadPoolExecutor方式,这一方面是由于jdk 中 Executor框架虽然提供了newFixedThreadPool(),newCacheThreadPool(),newSingleThreadExecutor() 等创建线程池的方法,但是都有局限性,不够灵活,而且前面的这几种方法内部也是通过ThreadPoolExecutor 方式实现,使用ThraedPoolExecutor有助于大家明确线程池的运行规则,创建符合符合自己业务场景需要的线程池,避免资源耗尽的风险。

ThreadPoolExector构造函数

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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

构造函数的参数含义如下:

corePoolSize:指定了线程池中线程的数量,它的数量决定了添加的任务是开辟新的线程去执行,还是放到workQueue中去执行;
maximumPoolSize:指定了线程池中的最大线程数量,这个参数会根据你使用的workQueue任务队列的类型,决定线程池会开辟的最大线程数量;
keepAliveTime:当线程池中空闲线程数量超过corePoolSize,多余的线程会在多长时间内被销毁;
unit:keppAliveTime的单位;
workQueu:任务队列,被添加到线程池中,但尚未被执行的任务;他一般分为直接提交队列,有界任务队列,无界任务队列,优先任务队列;
threadFactory:线程工厂,用于创建线程,一般使用默认就可以了;
handler:拒绝策略;当任务太多来不及处理时,如何拒绝任务;

1.添加任务到线程池
通过execute(Runable)方法被添加到线程池,任务就是一个Runable类型的对象,执行任务的方法就是Runable类型对象的run()方法。当一个任务通过execute(Runnable)方法欲添加到线程池时:

如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也会创建新的线程来处理被添加的任务;
如果此时线程池中的数量等于corePoolSize,但是缓冲队列workQueue未满,那么任务会被放入缓冲队列中;
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,创建新的线程来处理被添加的任务;
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过handler所指定的策略来处理任务;

也就是:处理任务的优先级为:
核心线程corePoolSize,任务队列workQueue,最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

当线程池中的数量大于corePoolSize时,如果某线程空闲时间超过keepAliveTime,该线程将会被终止。这样,线程池也可以动态调整线程池中的线程数量;

unit可选的参数为java.util.concurrent.TimeUnit中的几个静态属性:NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。

workQueue常用的是:java.util.concurrent.BlockingQueue

在这里插入图片描述从中可以发现ThreadPoolExecutor是依靠BlockingQueue的阻塞机制来维持线程池,当池子里的线程无事可干的时候就通过workQueue.take()阻塞住。

handler有4个选择:

ThreadPoolExecutor.Abortpolicy(); 抛出java.util.concurrent.RejectedExecutionException异常;
ThreadPoolExecutor.CallerPolicy(); 重试添加当前任务,他会自动重复调用execute()方法;
ThreadPoolExecutor.DiscardOldestPolicy();  抛弃旧的任务;
ThreadPoolExecutor.DiscardPolicy(); 抛弃当前任务;

2.线程池的使用场合
(1)单个任务处理的时间比较短;
(2)需要处理的任务数量大;

应用举例
package demo;

import java.io.Serializable;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExecutorDemo {

	private static int produceTaskSleepTime = 5;

	private static int consumeTaskSleepTime = 5000;

	private static int produceTaskMaxNumber = 20; // 定义最大添加20个线程到线程池中

	public static void main(String[] args) {
		// 构造一个线程池
		ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3, TimeUnit.SECONDS,
				new ArrayBlockingQueue<Runnable>(3), new ThreadPoolExecutor.DiscardOldestPolicy());

		for (int i = 1; i <= produceTaskMaxNumber; i++) {
			try {
				// 一个任务,并将其加入到线程池
				String work = "work@" + i;
				System.out.println("put:" + work);
				threadPool.execute(new ThreadPoolTask(work));
				// 便于观察,等待一段时间
				Thread.sleep(produceTaskSleepTime);

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static class ThreadPoolTask implements Runnable, Serializable {
		private static final long serialVersionUID = 0;

		// 保存任务所需要的数据
		private Object threadPoolTaskData;

		ThreadPoolTask(String work) {
			this.threadPoolTaskData = work;
		}

		public void run() {
			// 处理一个任务,这里的处理方式太简单了,仅仅是一个打印语句
			System.out.println("start-----" + threadPoolTaskData);
			try {
				// 便于观察,等待一段时间
				Thread.sleep(consumeTaskSleepTime);
			} catch (Exception e) {
				e.printStackTrace();
			}
			threadPoolTaskData = null;
		}

		public Object getTask() {
			return this.threadPoolTaskData;
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值