ThreadPoolExecutor线程池的简单应用

一、什么是线程池?
线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
二、线程池的优势

  • 第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

  • 第二:提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。

  • 第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。但是要做到合理的利用线程池,必须对其原理了如指掌。

三、ThreadPoolExecutor参数认知

  1. corePoolSize : 线程池的基本大小,当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。

  2. runnableTaskQueue:任务对列,用于保存等待执行的任务的阻塞队列。可以选择以下几个阻塞队列。

  • ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。

  • LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。

  • SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。

  • PriorityBlockingQueue:一个具有优先级得无限阻塞队列。

  1. maximumPoolSize:线程池最大大小,线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。

  2. ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字,Debug和定位问题时非常又帮助。

  3. RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。

  • CallerRunsPolicy:只用调用者所在线程来运行任务。

  • DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。

  • DiscardPolicy:不处理,丢弃掉。

  • 当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。

  1. keepAliveTime :线程活动保持时间,线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。

  2. TimeUnit:线程活动保持时间的单位,可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

四、ThreadPoolExecutor使用demo
封装Executors

package com.gm.thread.demo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Executors {

	/**
	 * 可控最大并发数线程池: 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
	 * @param name 线程作用
	 * @param corePoolSize 线程池的基本大小
	 * @return
	 */
	public static ExecutorService newFixedThreadPool(String name, int corePoolSize) {
		return new ThreadPoolExecutor(corePoolSize, corePoolSize, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue(),
				new NamedThreadFactory(name, true), new AbortPolicyWithReport(name));
	}
	
	/**
	 * 可回收缓存线程池: 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
	 * @param name 线程作用 
	 * @param corePoolSize 线程池的基本大小
	 * @param maximumPoolSize 线程池最大大小
	 * @return
	 */
	public static ExecutorService newCachedThreadPool(String name, int corePoolSize, int maximumPoolSize) {
		return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 180L, TimeUnit.SECONDS, new SynchronousQueue(),
				new NamedThreadFactory(name, true), new AbortPolicyWithReport(name));
	}
	
	/**
	 * 有界线程池:此线程池一直增长,直到上限,增长后不收缩(因为池子里面的线程是永生的)
	 * @param name 线程作用
	 * @param corePoolSize 线程池的基本大小
	 * @param maximumPoolSize 线程池最大大小
	 * @return
	 */
	public static ExecutorService newLimitedThreadPool(String name, int corePoolSize, int maximumPoolSize) {
		return new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 2147483647L, TimeUnit.SECONDS, new SynchronousQueue(),
				new NamedThreadFactory(name, true), new AbortPolicyWithReport(name));
	}
	
	/**
	 * 单线程化线程池:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
	 * @param name 线程作用
	 * @return
	 */
	public static ExecutorService newSingleThreadExecutor(String name) {
		return java.util.concurrent.Executors.newSingleThreadExecutor(new NamedThreadFactory(name, true));
	}
}

封装自定义线程工厂

package com.gm.thread.demo;

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class NamedThreadFactory implements ThreadFactory {
	private static final AtomicInteger POOL_SEQ = new AtomicInteger(1);
	
	private final AtomicInteger mThreadNum = new AtomicInteger(1);
	private final String mPrefix;
	private final boolean mDaemo;
	private final ThreadGroup mGroup;

	public NamedThreadFactory() {
		this("pool-" + POOL_SEQ.getAndIncrement(), false);
	}

	public NamedThreadFactory(String prefix) {
		this(prefix, false);
	}

	public NamedThreadFactory(String prefix, boolean daemo) {
		this.mPrefix = (prefix + "-thread-");
		this.mDaemo = daemo;
		
		/*
		 * SecurityManager(安全管理器)应用场景 当运行未知的Java程序的时候,该程序可能有恶意代码(删除系统文件、重启系统等),
		 * 为了防止运行恶意代码对系统产生影响,需要对运行的代码的权限进行控制, 这时候就要启用Java安全管理器。
		 */
		SecurityManager s = System.getSecurityManager();
		this.mGroup = (s == null ? Thread.currentThread().getThreadGroup() : s.getThreadGroup());
	}

	public Thread newThread(Runnable runnable) {
		String name = this.mPrefix + this.mThreadNum.getAndIncrement();
		Thread ret = new Thread(this.mGroup, runnable, name, 0L);
		ret.setDaemon(this.mDaemo);
		return ret;
	}

	public ThreadGroup getThreadGroup() {
		return this.mGroup;
	}
}

封装自定义RejectedExecutionHandler(饱和策略)

package com.gm.thread.demo;

import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AbortPolicyWithReport extends ThreadPoolExecutor.AbortPolicy {
	protected static final Logger logger = LoggerFactory.getLogger(AbortPolicyWithReport.class);
	private final String threadName;
	private static final String ERROR = "Thread pool is EXHAUSTED! Thread Name: %s, Pool Size: %d (active: %d, core: %d, max: %d, largest: %d), Task: %d (completed: %d), Executor status:(isShutdown:%s, isTerminated:%s, isTerminating:%s)!";

	public AbortPolicyWithReport(String threadName) {
		this.threadName = threadName;
	}

	public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
		String msg = String.format(
				ERROR,
				new Object[] { this.threadName, 
						Integer.valueOf(e.getPoolSize()), 
						Integer.valueOf(e.getActiveCount()),
						Integer.valueOf(e.getCorePoolSize()), 
						Integer.valueOf(e.getMaximumPoolSize()),
						Integer.valueOf(e.getLargestPoolSize()), 
						Long.valueOf(e.getTaskCount()),
						Long.valueOf(e.getCompletedTaskCount()), 
						Boolean.valueOf(e.isShutdown()),
						Boolean.valueOf(e.isTerminated()), 
						Boolean.valueOf(e.isTerminating())});

		logger.warn(msg);
		throw new RejectedExecutionException(msg);
	}
}

使用demo

package com.gm.thread.demo;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Semaphore;

public class ThreadPoolDemo {

	private int corePoolSize = 10;
	private int maximumPoolSize = 10;

	private ExecutorService exe = null;

	private Semaphore available = null;
	
	public void execute(){
		
		if(exe==null){
			exe = Executors.newCachedThreadPool("this thread is a demo", corePoolSize,
					maximumPoolSize);
		}
		
		if(available==null){
			available = new Semaphore(maximumPoolSize);
		}
		/*
		 * 模拟从数据库中查询出的数据,比如发生退款时,对接方没有异步通知,
		 * 所以需要从第三方获取退款状态
		 */
		List<Integer> list = new ArrayList<>();
//		for (int i = 0; i < 10; i++) {
//			list.add(i++);
//		}
		if (list != null) {
			for (Integer integer : list) {
				//方法acquireUninterruptibly()的作用是使等待进入acquire()方法的线程,不允许被中断。
				available.acquireUninterruptibly();
				exe.execute(new Runnable() {
					
					@Override
					public void run() {
						System.out.println("当前线程"+Thread.currentThread().getName()+"请求第三方接口");
					}
					
				});
			}
		}
	}
	
	public static void main(String[] args) {
		new ThreadPoolDemo().execute();
	}
}

如此,我们一个小小的ThreadPoolExecutor的例子完成了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值