一、什么是线程池?
线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
二、线程池的优势
-
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
-
第二:提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
-
第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。但是要做到合理的利用线程池,必须对其原理了如指掌。
三、ThreadPoolExecutor参数认知
-
corePoolSize : 线程池的基本大小,当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。
-
runnableTaskQueue:任务对列,用于保存等待执行的任务的阻塞队列。可以选择以下几个阻塞队列。
-
ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
-
LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
-
SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
-
PriorityBlockingQueue:一个具有优先级得无限阻塞队列。
-
maximumPoolSize:线程池最大大小,线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。
-
ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字,Debug和定位问题时非常又帮助。
-
RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。
-
CallerRunsPolicy:只用调用者所在线程来运行任务。
-
DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
-
DiscardPolicy:不处理,丢弃掉。
-
当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
-
keepAliveTime :线程活动保持时间,线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。
-
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的例子完成了。