Java线程池入门必备
来源:互联网 发布:java集成极光推送 编辑:程序博客网 时间:2024/06/16 05:46
线程池
一. 线程池的简介
1.什么是线程池?
最早期的工作线程处理任务的模型。一个任务的到来,会伴随着线程的创建,当处理完任务后,线程会被销毁,资源回收。这种一个任务一个线程一系列创建销毁的模式,缺陷毋庸置疑.不仅是线程创建销毁带来的系统开销,也不好管理工作线程。于是引入了“线程池”的概念。它是一种预创建线程的技术。每次线程执行完任务前,先把任务委派给线程池空闲的线程, 如果没有空闲的线程, 则根据线程池任务策略执行。处理完任务后, 线程不会直接被销毁掉,会放到线程池管理。
2.线程池有何作用?
线程池的作用, 个人理解主要有三点。
减少系统资源的开销 :避免新线程的创建、销毁等繁琐过程。
提供系统的性能 : 池至少有一个以上的线程, 多线程协同工作, 可响应多个客户端请求。而且可以重复利用池里空闲的线程,免去了新线程不断地创建、销毁过程.
提高系统稳定性 :一个请求一个线程处理, 高并发请求下, 系统不得不创建大量线程来接活。大量的线程创建、销毁会占用系统大量资源, 最终耗光系统资源, 导致系统宕机。引入线程池后,能根据系统的承载能力, 调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
二. 线程池的创建
线程池的创建入口Executors.真正干活的是ExecutorService
newFixedThreadPool
- 说明
创建固定大小的线程池。每次提交一个任务,就会启一个线程来接客,直到线程池的线程数量达到线程池的上限。
- demo
public class PoolDemo { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(2); for(int i = 0; i<5; i++) { executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); } executorService.shutdown(); }}result :pool-1-thread-1pool-1-thread-2pool-1-thread-1pool-1-thread-2pool-1-thread-1
newCachedThreadPool
- 说明
创建一个可缓存的线程池。每次提交一个任务,委派给线程池空闲的线程处理, 如果木有空闲的线程, 则直接创建新线程,任务被执行完后,当前线程加入到线程池维护。其生命周期超过一定时间会被销毁回收。
- demo
public class PoolDemo { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); for(int i = 0; i<5; i++) { executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); } executorService.shutdown(); }}result:pool-1-thread-1pool-1-thread-2pool-1-thread-4pool-1-thread-3pool-1-thread-5
- newSingleThreadExecutor
- 说明
创建只有一个线程的线程池。问题来了, 一个线程的线程池和普通创建一个线程一样么?当然不一样.线程销毁问题。
- demo
public class PoolDemo { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); for(int i = 0; i<5; i++) { executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); } executorService.shutdown(); }}result:pool-1-thread-1pool-1-thread-1pool-1-thread-1pool-1-thread-1pool-1-thread-1
newScheduledThreadPool
- 说明
创建一个大小不受限的线程池。提供定时、周期地执行任务能力。
- demo
public class PoolDemo { public static void main(String[] args) { ExecutorService executorService = Executors.newScheduledThreadPool(2); for(int i = 0; i<5; i++) { executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); } executorService.shutdown(); }}result:pool-1-thread-1pool-1-thread-1pool-1-thread-1pool-1-thread-2pool-1-thread-1
- 定时周期执行demo2
public class PoolDemo { public static void main(String[] args) { ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2); long initialDelay = 1, delay = 1; // 应用启动1S后,每隔1S执行一次 executorService.scheduleWithFixedDelay(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }, initialDelay, delay, TimeUnit.SECONDS); // 应用启动1S后,每隔2S执行一次 executorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }, initialDelay, delay, TimeUnit.SECONDS); }}
拓展scheduleWithFixedDelay | scheduleAtFixedRate 区别
看下源码注释
- scheduleAtFixedRate
/** * Creates and executes a periodic action that becomes enabled first * after the given initial delay, and subsequently with the given * period; that is executions will commence after * {@code initialDelay} then {@code initialDelay+period}, then * {@code initialDelay + 2 * period}, and so on. * If any execution of the task * encounters an exception, subsequent executions are suppressed. * Otherwise, the task will only terminate via cancellation or * termination of the executor. If any execution of this task * takes longer than its period, then subsequent executions * may start late, but will not concurrently execute. * * @param command the task to execute * @param initialDelay the time to delay first execution * @param period the period between successive executions * @param unit the time unit of the initialDelay and period parameters * @return a ScheduledFuture representing pending completion of * the task, and whose {@code get()} method will throw an * exception upon cancellation * @throws RejectedExecutionException if the task cannot be * scheduled for execution * @throws NullPointerException if command is null * @throws IllegalArgumentException if period less than or equal to zero */ public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
- scheduleWithFixedDelay
/** * Creates and executes a periodic action that becomes enabled first * after the given initial delay, and subsequently with the * given delay between the termination of one execution and the * commencement of the next. If any execution of the task * encounters an exception, subsequent executions are suppressed. * Otherwise, the task will only terminate via cancellation or * termination of the executor. * * @param command the task to execute * @param initialDelay the time to delay first execution * @param delay the delay between the termination of one * execution and the commencement of the next * @param unit the time unit of the initialDelay and delay parameters * @return a ScheduledFuture representing pending completion of * the task, and whose {@code get()} method will throw an * exception upon cancellation * @throws RejectedExecutionException if the task cannot be * scheduled for execution * @throws NullPointerException if command is null * @throws IllegalArgumentException if delay less than or equal to zero */ public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);
不难得出如下结论:
ScheduledExecutorService 中两种最常用的调度方法 ScheduleAtFixedRate 和 ScheduleWithFixedDelay。ScheduleAtFixedRate 每次执行时间为上一次任务开始起向后推一个时间间隔,即每次执行时间为 :initialDelay, initialDelay+period, initialDelay+2*period, …;ScheduleWithFixedDelay 每次执行时间为上一次任务结束起向后推一个时间间隔,即每次执行时间为:initialDelay, initialDelay+executeTime+delay, initialDelay+2*executeTime+2*delay。由此可见,ScheduleAtFixedRate 是基于固定时间间隔进行任务调度,ScheduleWithFixedDelay 取决于每次任务执行的时间长短,是基于不固定时间间隔进行任务调度。
三. 线程池的拒绝策略
线程池的拒绝策略是干嘛来的?它是在应接不暇的时候, 对新任务采取的执行策略(执行?丢弃and so on). RejectedExecutionHandler是拒绝任务策略的基础接口, Jdk提供了四种拒绝策略。
1.CallerRunsPolicy
这种策略是说线程池在没被关闭前, 直接会去执行此任务, 否则丢弃任务。
/** * A handler for rejected tasks that runs the rejected task * directly in the calling thread of the {@code execute} method, * unless the executor has been shut down, in which case the task * is discarded. */ public static class CallerRunsPolicy implements RejectedExecutionHandler { /** * Creates a {@code CallerRunsPolicy}. */ public CallerRunsPolicy() { } /** * Executes task r in the caller's thread, unless the executor * has been shut down, in which case the task is discarded. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }
2.AbortPolicy
AbortPolicy线程拒绝策略,简单粗暴, 直接throw exception出来了, 丢弃任务
/** * A handler for rejected tasks that throws a * {@code RejectedExecutionException}. */ public static class AbortPolicy implements RejectedExecutionHandler { /** * Creates an {@code AbortPolicy}. */ public AbortPolicy() { } /** * Always throws RejectedExecutionException. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task * @throws RejectedExecutionException always */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); } }
3.DiscardPolicy
DiscardPolicy策略跟AbortPolicy一样, 直接丢弃任务, 只不过人家不抛出exception罢了。
/** * A handler for rejected tasks that silently discards the * rejected task. */ public static class DiscardPolicy implements RejectedExecutionHandler { /** * Creates a {@code DiscardPolicy}. */ public DiscardPolicy() { } /** * Does nothing, which has the effect of discarding task r. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } }
4.DiscardOldestPolicy
DiscardOldestPolicy策略, 是在线程池没被关闭的情况下, 丢弃任务等待队列中最早的任务。然后重新尝试运行该任务。
/** * A handler for rejected tasks that discards the oldest unhandled * request and then retries {@code execute}, unless the executor * is shut down, in which case the task is discarded. */ public static class DiscardOldestPolicy implements RejectedExecutionHandler { /** * Creates a {@code DiscardOldestPolicy} for the given executor. */ public DiscardOldestPolicy() { } /** * Obtains and ignores the next task that the executor * would otherwise execute, if one is immediately available, * and then retries execution of task r, unless the executor * is shut down, in which case task r is instead discarded. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }
- Java线程池入门必备
- Java线程池知识必备
- Java线程池入门
- Java线程进程必备知识
- java面试必备之多线程
- java必备——进程?线程?
- java疑难31问,入门必备
- 2012-5-20 JAVA入门基本概念必备
- IT行业、前端、java入门必备书籍
- java学习入门必备:循环语句
- java多线程(四) 之 线程池入门
- Scala入门学习之 【Java线程池】
- java线程入门
- Java线程入门
- java 线程入门
- Java入门, 线程
- java线程入门
- JAVA 线程使用入门
- log4j .properties
- 人类对敏捷开发与软件工程的三种认知与行为
- Eclipse重新定位svn资源库
- 详解JS数据类型
- Java设置session超时(失效)的三种方式
- Java线程池入门必备
- JSP中的异常处理
- 剑指offer——二叉搜索树与双向链表
- 模式识别感知器算法C++写的
- 对万向节锁的理解
- TCP/IP协议中的端口
- 几款流行开源ESB总线简介
- ARP协议以及获取当前局域下主机MAC地址
- adb remount 系统提示只读文件系统Read-only file system,解决用adb disable-verity