文章目录
线程池介绍
池,从字面意思来说,就是将一定的数量放到一起,进行统一的管理和限制,从而达到统一使用线程的方式。
线程池的好处
降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
线程池一般用于执行多个不相关联的耗时任务,没有多线程的情况下,任务顺序执行,使用了线程池的话可让多个不相关联的任务同时执行。
线程池参数解析
java
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;
}
这是java源码中线程池创建需要的参数
corePoolSize
:核心线程数量,在任务数量没有达到核心线程数量时,也会保持的线程数量maximumPoolSize
:任务队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。keepAliveTime
:线程池中的线程数量大于corePoolSize
的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了keepAliveTime
才会被回收销毁。unit
:keepAliveTime的单位workQueue
:当有新的任务出现,会先判断当前线程数是否达到核心线程数量,如果达到就将任务放入阻塞队列workQueue中threadFactory
:线程工厂,为线程池创造线程hander
:拒绝策略(重点)
ThreadPoolExcutor拒绝策略
ThreadPoolExecutor.AbortPolicy
:抛出 RejectedExecutionException
来拒绝新任务的处理。
ThreadPoolExecutor.CallerRunsPolicy
:调用执行自己的线程运行任务,也就是直接在调用execute
方法的线程中运行(run
)被拒绝的任务,如果执行程序已关闭,则会丢弃该任务。因此这种策略会降低对于新任务提交速度,影响程序的整体性能。如果您的应用程序可以承受此延迟并且你要求任何一个任务请求都要被执行的话,你可以选择这个策略。
ThreadPoolExecutor.DiscardPolicy
:不处理新任务,直接丢弃掉。
ThreadPoolExecutor.DiscardOldestPolicy
:此策略将丢弃最早的未处理的任务请求。
简单来说,就是当你今天上班任务已经排满了,但是老板非要给你再加一项任务,此时你会作出一下操作:
- 直接拒绝老板
- 表示自己不会做,并且指出谁提出,谁负责
- 将自己最早的任务丢弃,来执行新任务
- 将老板给的任务直接丢弃
线程池使用案例
方式一:使用ThreadPoolExecutor
java
public static void main(String[] args) {
ExecutorService service1=Executors.newSingleThreadExecutor();
ThreadFactory threadFactory=Executors.defaultThreadFactory();
BlockingQueue<Runnable> workqueue=new ArrayBlockingQueue<>(100);
ThreadPoolExecutor poolExecutor=new ThreadPoolExecutor(10,20,10, TimeUnit.SECONDS,workqueue,threadFactory);
for(int i=0;i<1000;i++){
int a=i;
poolExecutor.submit(new Runnable() {
@Override
public void run() {
System.out.println(a+" "+Thread.currentThread().getName());
}
});
}
poolExecutor.shutdownNow();
}
方法二:使用Executors
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
ExecutorService temp=Executors.newFixedThreadPool(10);
ExecutorService service1=Executors.newSingleThreadExecutor();
ExecutorService service2=Executors.newScheduledThreadPool(10);
for(int i=0;i<1000;i++){
int a=i;
poolExecutor.submit(new Runnable() {
@Override
public void run() {
System.out.println(a+" "+Thread.currentThread().getName());
}
});
}
poolExecutor.shutdownNow();
}
FixedThreadPool
:固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
SingleThreadExecutor
: 只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。
CachedThreadPool
: 可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复用。
ScheduledThreadPool
:给定的延迟后运行任务或者定期执行任务的线程池。