Java线程池
线程池的有点
1.降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
2.提高响应速度,任务可以不需要等线程创建就能立即执行。
3.提高线程可管理性,防止无限制创建导致的消耗系统资源、降低系统稳定性。使用线程池可以进行统一的分配、调优和监控。
4.使用线程池可以有效控制最大并发线程数,提高资源利用率,避免过多资源竞争,避免阻塞。
5.线程池可以提供定时执行、单线程执行、并发控制等,操作线程方便。
6.new Thread不能重复使用,new 相当于在内存中单独开辟一个内存让线程运行,需要释放线程和新建线程,性能差。使用线程池,可以减少对象的创建、消亡的开销。
线程池简介
Java中,线程池的概念是Executor这个接口,具体实现为ThreadPoolExecutor类。对线程池的配置,就是对ThreadPoolExecutor构造函数的参数配置。
ThreadPoolExecutor提供了四个构造函数:
ThreadPoolExecutor策略:
1.线程数量未达到corePoolSize,新建一个线程(核心线程)执行任务
2.线程数量达到corePoolSize,则任务加入列等待。
3.队列已满,新建线程(非核心线程)执行任务。
4.队列已满,总线程数又达到maximumPoolSize,抛出异常。
ThreadPoolExecutor的参数和方法
corePoolSize:核心线程数量。当线程数少于corePoolSize的时候,直接创建新的线程,尽管其他的线程是空闲的。当线程池中的线程数目达到corePoolSize后,会把到达的任务放到缓存队列中。
maximunPoolSize:线程池最大线程数。线程数少于线程最大数目且大于核心线程数目的时候,只有当阻塞队列满了才创建新线程。当线程数量大于最大线程数目且阻塞队列满了是会执行一些策略来影响该线程。
workQueue:阻塞队列,存储等待执行的任务。当所有核心线程都执行时,新增加任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行。
常用workQueue类型:
SynchronousQueue:接收任务后直接给线程处理,如果线程都在工作,就创建新线程。为了不保证达到最大线程数,maximumPoolSize一般指定无限大。
LinkedBlockingQueue:当线程数小于核心线程数则新建线程,如果等于核心线程数,则进入等待队列,由于队列没有最大限制,即所有超过线程线程数的线程都被添加到该队列中,导致maximumPoolSize设定失效。
ArrayBlockingQueue:可限定队列长度,如果没有达到核心线程数,则新建核心线程,如果达到了,则入队等候,如果队列已满,则新建线程(非核心线程),如果达到最大限制数,并且队列也满了,则发生错误。
DelayQueue:队列元素必须实现Delayed接口,队列接收任务时,首先先入队,达到指定延时时间才会执行。
keepAliveTime:非核心线程没有任务执行最多保持多久时间终止。
allowCoreThreadTimeOut=true:上面的时间作用于核心线程。
unit:keepAliveTime的时间单位
threadFactory:线程工厂,用来创建线程。使用默认工厂创建线程时,线程具有相同的优先级。
handler:拒绝策略。
execute();添加任务。
submit();提交任务,返回execute+Future。
invokeAll();方法接收一个list<Callable>,当全部任务都执行完成后返回List<Future<T>>,并且能保证请求和返回值的顺序是一致的。
shutdown();关闭线程池,等待任务都执行完。
shutdownNow();关闭线程池,不等待任务执行完。
getTaskCount();线程池已执行和未执行的任务总数。
getCompletedTaskCount();已完成的任务数量。
getPoolSize();当前线程数量。
getActiveCount();正在执行任务的线程数量。
Executor线程池创建的四种线程
1. newFixedThreadPool:创建的是定长的线程池,可以控制线程最大并发数,超出的线程会等待,使用*队列,核心线程数和最大线程数一样,当线程没有任务时立刻销毁。
2. newSingleThreadExecutor:创建的是单线程化的线程池,只会用唯一一个线程执行,可以指定是否按照先入先出,还是优先级来执行。是*队列,核心线程数和最大线程数都是1个。
3. newCachedThreadPool:设定一个可缓存的线程池,当线程池长度超过处理的需要,可以灵活回收空闲线程,如果没有可回收才创建新线程。没有核心线程数,当线程没任务60s后就会回收空闲线程,有界队列。
4. newScheduledThreadPool:支持线程定时操作和周期性操作。
常用四种线程池方法
CachedThreadPool()
可缓存线程池:
1.线程数无限制
2.有空闲则复用空闲线程,若无空闲线程则新建线程。
3.一定程序减少频繁创建/销毁线程,减少系统开销。
创建方法:ExccutorServicecachedThreadPool=Executors.newCachedThreadPool();
FixedThreadPool()
定长线程池:
1.可控制线程最大并发数。
2.超出的线程会在队列中等待。
创建方法:
ExecutorService fixedThreadPool=Executors.newFixedThreadPool(int maximumPoolSize);
ScheduledThreadPool()
定长线程池
执行定时及周期性任务执行。
ExecutorServicescheduledThreadPool=Executors.newScheduledThreadPool(int corePoolSize);
SingleThreadExecutor()
单线程化的线程池
1.仅有一个线程执行任务
2.所有任务按照指定顺序执行,遵循队列的入队出队规则。
创建方法:
ExecutorServicesingleThreadPool=Executor.newSingleThreadPool();
使用例子
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(15); fixedThreadPool.submit(() -> { System.out.println("test"); }));
ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor( 8, maxPoolSize, keepAlive, TimeUnit.SECONDS, new SynchronousQueue<>(), new ThreadFactoryBuilder().setNamePrefix("text-").build()); threadPoolExecutor.invokeAll(new LinkedList<Callable<Object>>(), 3, TimeUnit.MINUTES);