网站集约化建设讲话,网站开发心得,网站获取访客手机号源码,门户网站建设申请目录
Java线程池
处理流程
线程池主要参数
常见的拒绝策略
execute和submit区别
关闭线程池
常见的线程池
newSingleThreadExecutor
newFixedThreadPool
newCachedThreadPool
newScheduledThreadPool
线程池的状态 Java线程池
运用场景最多的并发框架#xff0c;…目录
Java线程池
处理流程
线程池主要参数
常见的拒绝策略
execute和submit区别
关闭线程池
常见的线程池
newSingleThreadExecutor
newFixedThreadPool
newCachedThreadPool
newScheduledThreadPool
线程池的状态 Java线程池
运用场景最多的并发框架几乎所有需要异步或者并发执行任务的程序都可以使用线程池。如下好处 降低资源消耗。重复利用已创建的线程降低线程创建和销毁造成的消耗。 提高响应速度。当任务到达时不需要等到线程创建就能立即执行。 提高线程的客观理性。使用线程池可以进行统一分配、调优和监控。
处理流程
当新任务到达线程池的时候处理流程如下 判断核心线程池里的线程是否都在执行任务 否创建新的工作线程执行任务。 是去看阻塞队列。 判断阻塞队列是否满了 否将新任务存储在阻塞队列中。 是去看整个线程池。 判断线程池的线程是否都处于工作状态 否创建新的工作线程执行任务。 是去看拒绝策略吧。 根据拒绝策略进行处理。 ThreadPoolExecutor执行execute方法分为下面4中情况 当前运行的线程少于corePoolSize创建新线程执行任务。(需获取全局锁) 运行的线程等于或多余corePoolSize则将任务加入BlockingQueue。 如果队列已满且运行线程数少于maximumPoolSize创建新线程执行任务。需获取全局锁 如果创建新线程将使得当前运行的线程超过maximumPoolSize任务被拒绝执行RejectedExecutionHandler.rejectedExecution()方法。 网上有看到一个生动的例子可能会让大家印象更深刻些
银行的营业大厅有6个业务窗口现在开放了3个有3个业务员负责办理业务。这天二柱去办理业务他可能会遇到什么情况呢 3个业务窗口正好空闲他可以直接去办理业务。 3个业务窗口都有人所以他得去排队。 3个业务窗口都有人而且队也排满了。这是经理赶紧开放了另外3个窗口排队的可以先去办理。 6个业务窗口都有人了队伍也排满了。二柱子去找经理经理说明天再来或者先不办了。
线程池主要参数 核心线程数corePoolSize 核心线程数是线程池中保持活动状态的最小线程数量。即使线程池中没有任务需要执行核心线程也会保持活动状态不会被销毁。核心线程数通常用来处理短期生存期的任务以减少线程的创建和销毁开销。 最大线程数maximumPoolSize 最大线程数是线程池中允许存在的最大线程数量。当任务数量超过核心线程数并且任务队列已满时线程池会创建新的线程但不会超过最大线程数。最大线程数可以控制线程池的最大并发性。 任务队列BlockingQueue 任务队列用于存储等待执行的任务。当线程池中的线程数达到核心线程数时新的任务会被放入任务队列中等待执行。任务队列可以是不同类型的队列如无界队列如 LinkedBlockingQueue或有界队列如 ArrayBlockingQueue。 线程存活时间keepAliveTime 线程存活时间是在核心线程数之外的线程在没有任务可执行时保持活动状态的最长时间。当线程池中的线程数量超过核心线程数空闲的非核心线程在经过一定时间后会被销毁以减少资源占用。 拒绝策略RejectedExecutionHandler 拒绝策略定义了当线程池无法接受新的任务时应该采取的动作。常见的拒绝策略包括抛出异常、丢弃任务、丢弃最旧的任务、调用提交任务的线程来执行任务等。 线程工厂ThreadFactory 线程工厂用于创建线程池中的线程。通过自定义线程工厂可以为线程池中的线程设置自定义的名称、优先级、守护状态等属性。
常见的拒绝策略 AbortPolicy默认策略 这是默认的拒绝策略它会抛出一个 RejectedExecutionException 异常告诉调用者线程池已满无法处理新任务。这是最常用的拒绝策略它会防止任务堆积但可能会导致任务丢失。 ThreadPoolExecutor executor new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue,new ThreadPoolExecutor.AbortPolicy()); CallerRunsPolicy 这个策略不会抛出异常而是将任务回退到调用者让调用者来执行。这可以用于保证任务的执行但可能会导致调用者的线程阻塞。 ThreadPoolExecutor executor new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue,new ThreadPoolExecutor.CallerRunsPolicy()); DiscardPolicy 这个策略会默默地丢弃掉无法处理的新任务不会抛出异常。这可能会导致任务丢失但对于不太重要的任务可以使用。 ThreadPoolExecutor executor new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue,new ThreadPoolExecutor.DiscardPolicy()); DiscardOldestPolicy 这个策略会丢弃队列中最旧的任务然后尝试重新提交新任务。它可能会导致一些任务被丢弃但对于有优先级的任务可能是一个不错的选择。 ThreadPoolExecutor executor new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue,new ThreadPoolExecutor.DiscardOldestPolicy()); 自定义策略 你也可以自定义拒绝策略只需实现 RejectedExecutionHandler 接口的 rejectedExecution 方法然后将其传递给线程池的构造函数。 class CustomRejectPolicy implements RejectedExecutionHandler {Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {// 自定义拒绝策略的逻辑}
}
ThreadPoolExecutor executor new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue,new CustomRejectPolicy());
选择适当的拒绝策略取决于应用程序的需求。通常如果任务的重要性很高你可能会选择将任务回退到调用者或者使用自定义策略来处理。如果任务不太重要你可以使用默认的 AbortPolicy 或 DiscardPolicy 策略。需要根据具体情况权衡任务的执行和资源利用之间的权衡。
execute和submit区别
可以使用两个方法向线程池提交任务分别为execute()和submit()方法。
execute()方法用于提交不需要返回值的任务。 threadsPool.execute(new Runnable() { Override public void run() { // TODO Auto-generated method stub } });
submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象通过这个 future对象可以判断任务是否执行成功并且可以通过future的get()方法来获取返回值get()方 法会阻塞当前线程直到任务完成而使用getlong timeoutTimeUnit unit方法则会阻塞当前线 程一段时间后立即返回这时候有可能任务没有执行完。
Future future executor.submit(harReturnValuetask); try { Object s future.get(); } catch (InterruptedException e) { // 处理中断异常 } catch (ExecutionException e) { // 处理无法执行任务异常 } finally { // 关闭线程池 executor.shutdown(); }
关闭线程池
可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池。它们的原理是遍历线程池中的工作线程然后逐个调用线程的interrupt方法来中断线程所以无法响应中断的任务可能永远无法终止。
shutdown() 将线程池状态置为shutdown,并不会⽴即停⽌ 停⽌接收外部submit的任务 内部正在跑的任务和队列⾥等待的任务会执⾏完 等到第⼆步完成后才真正停⽌
shutdownNow() 将线程池状态置为stop。⼀般会⽴即停⽌事实上不⼀定 和shutdown()⼀样先停⽌接收外部提交的任务 忽略队列⾥等待的任务 尝试将正在跑的任务interrupt中断 返回未执⾏的任务列表
shutdown 和shutdownnow简单来说区别如下 shutdownNow()能⽴即停⽌线程池正在跑的和正在等待的任务都停下了。这样做⽴即⽣效但是⻛险也⽐ 较⼤。 shutdown()只是关闭了提交通道⽤submit()是⽆效的⽽内部的任务该怎么跑还是怎么跑跑完再彻底停 ⽌线程池。
常见的线程池
常见的有四种都是通过Executors 工具类创建的但是不建议。Executors各个方法的弊端newFixedThreadPool和newSingleThreadExecutor: 主要问题是堆积的请求处理队列可能会耗费非常大的内存甚至OOM。
newCachedThreadPool和newScheduledThreadPool: 主要问题是线程数最大数是Integer.MAX_VALUE可能会创建数量非常多的线程甚至OOM。 newSingleThreadExecutor
直接调用ThreadPoolExecutor的构造⽅法。
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueueRunnable(), threadFactory));
}
线程池特点 核心线程数1 最大线程数1 阻塞队列是无界队列LinkedBlockingQueue可能会导致OOM keepAliveTime为0
使用场景串行执行任务的场景一个任务一个任务地执行
newFixedThreadPool
直接调用ThreadPoolExecutor的构造⽅法。
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueueRunnable(), threadFactory);
}
线程池特点 核心线程数和最大线程数大小一样 keepAliveTime为0 阻塞队列是无界队列LinkedBlockingQueue可能会导致OOM
使用场景适用于执行长期的任务
newCachedThreadPool
直接调用ThreadPoolExecutor的构造⽅法。
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueueRunnable(), threadFactory);
}
线程池特点 核心线程数0 最大线程数Integer.MAX_VALUE可能无限创建线程导致OOM 阻塞队列是SynchronousQueue 非核心线程空闲存活时间为60s
使用场景并发执行大量短期的小任务
newScheduledThreadPool
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
}
线程池特点 最大线程数Integer.MAX_VALUE可能无限创建线程导致OOM 阻塞队列DelayedWorkQueue keepAliveTime为0 scheduleAtFixedRate() 按某种速率周期执⾏ scheduleWithFixedDelay()在某个延迟后执⾏
使用场景周期性执行任务的场景需要限制线程数量的场景
线程池的状态 RUNNING运行中 线程池处于运行状态可以接受新的任务并且正在执行任务队列中的任务。 SHUTDOWN关闭中 线程池进入关闭状态不再接受新的任务提交但会继续执行已经提交的任务直到所有任务都完成。 STOP停止中 线程池进入停止状态不再接受新的任务提交并且尝试中断正在执行的任务。这个状态会尽量终止线程池的执行。 TIDYING整理中 线程池正在执行清理操作。当线程池的任务都完成后它会进入这个状态执行一些必要的清理操作例如关闭线程。 TERMINATED已终止 线程池已经完全终止不再有任何活动线程。线程池的状态将永远停留在这个状态。
线程池的状态通常通过调用线程池的方法来进行转换例如 shutdown() 方法将线程池从 RUNNING 状态转换为 SHUTDOWN 状态shutdownNow() 方法将线程池从 RUNNING 状态转换为 STOP 状态。一旦线程池进入 TERMINATED 状态就无法再切换到其他状态。