线程池学习总结
关于线程状态的学习文章链接
什么是线程池?
线程池是一种多线程处理形式,处理过程中将任务提交到线程池,任务的执行交由线程池来管理。
如果每个请求都创建一个线程去处理,那么服务器的资源很快就会被耗尽,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
线程池状态:
- RUNNING:运行状态,这个状态下可以接受任务来处理
- SHUTDOWN:待关闭状态,这个状态下不会在接受新任务,但是仍然会处理阻塞队列中的任务,当阻塞队列中的任务为空,并且工作线程数为0时,进入
TIDYING 状态 - STOP:停止状态,不会接受新任务,并且也不处理阻塞队列中的任务,并且会尝试结束执行中的任务,当阻塞队列为空,并且工作线程数为0时,进入
TIDYING 状态 - TIDYING:整理状态,此时任务都已经执行完毕,并且也没有工作线程执行 terminated 方法后进入 TERMINATED 状态
- TERMINATED:终止状态,此时线程池完全终止了,并完成了所有资源的释放
线程池参数:
核心线程数、最大线程数、阻塞队列,时间、拒绝策略。
线程池如何处理任务的?
当程序提交一个任务时,线程池会比较当前工作线程数和核心线程数,如果前者小于后者,线程池直接新建一个线程来处理这个任务,如果前者大于后者,则会将这个任务放到阻塞队列中等待被处理,如果队列满了,线程池会建立“临时”工作线程来处理队列的任务,如果工作线程数达到最大线程数,线程池会做出拒绝策略。
ps:当工作线程数量大于核心线程数,线程池会回收掉那些线程等待任务时间超时的线程,这里就要关系到使用task()、poll()方法的区别了
拒绝策略:
- 抛出异常(默认)
- 调用者线程来处理这个任务
- 从阻塞队列中找最老的任务,将其丢弃,然后提交该任务
- 将请求任务丢弃
AbortPolicy – 当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException异常。
CallerRunsPolicy --当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。
DiscardOldestPolicy --当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。
DiscardPolicy – 当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。
java.util.concurrent.Executors常用的几种线程池类型
- newSingleThreadExecutor:一个单线程的线程池,可以用于需要保证顺序执行的场景,并且只有一个线程在执行。
- newFixedThreadPool:一个固定大小的线程池,可以用于已知并发压力的情况下,对线程数做限制。(队列)
- newCachedThreadPool:一个可以无限扩大的线程池,比较适合处理执行时间比较小的任务。
- newScheduledThreadPool:可以延时启动,定时启动的线程池,适用于需要多个后台线程执行周期任务的场景。
自定义线程池
通过ThreadPoolExecutor
来实现自定义的线程池
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,//线程最大生命周期
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) ;
Demo
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
import java.util.concurrent.TimeUnit;
/**
*了解上面的参数信息后我们就可以定义自己的线程池了,我这边用ArrayBlockingQueue替换了LinkedBlockingQueue,指定了队列的大小,当任务超出队列大小之后使用CallerRunsPolicy拒绝策略处理。
这样做的好处是严格控制了队列的大小,不会出现一直往里面添加任务的情况,有的时候任务处理的比较慢,任务数量过多会占用大量内存,导致内存溢出。
*/
public class BengHiongThreadPoolExecutor {
private static ExecutorService executorService = newFixedThreadPool1(50);
private static ExecutorService newFixedThreadPool1(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10000), new DefaultThreadFactory(), new CallerRunsPolicy());
}
public static void execute(Runnable command) {
executorService.execute(command);
}
public static void shutdown() {
executorService.shutdown();
}
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "FSH-pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
}
总结:
线程池技术应用在多线程的场景可以节省很多资源消耗,提高性能,要用好先尝尝,要知道他的原理以及一些设定方法,才能更好的运用在实际中。
参考:
https://mp.weixin.qq.com/s/tvxF74r-NO2uiNIBebPjmQ
https://blog.csdn.net/j3T9Z7H/article/details/80730038