先从线程说起,我们创建线程的方法有几种:
1:继承Thread
2:实现Runnable
3:实现Callable(带返回值的)
项目中为什么以上这些方式直接创建线程呢?
每次创建线程都需要由os去操作系统成面创建线程之后,在调用我们的的重写的run方法,使用完了之后在调用os销毁线程,频繁创建和销毁大量线程需要消耗大量时间和资源。
java 线程池可以很好的解决这些问题:
1. 线程池是一次性创建指定数的线程,放到池中管理。
2. 减少了每个任务的调用开销,且执行大量异步任务时对性能进行了改进。
3. 每次使用完之后将使用完的线程放回线程池,减少了销毁的时间与资源。
4. 又因为线程都是放在统一的线程池中,可以很好的统一管理,调优以及监控。
java线程池的创建:
1. 可以使用线程池Executors工厂方法创建:
Executors.newCachedThreadPool()(无界线程池,具有自动线程回收功能)
Executors.newFixedThreadPool(int) (固定大小的线程池)
Executors.newSingleThreadExecutor()(单个后台线程)
2. 直接使用 new ThreadPoolExecutor() 创建,自己指定核心参数,核心参数详解如下:
corePoolSize(核心线程):核心线程数,线程池中常驻线程的最大数量。
当在方法中提交了一个新任务,并且运行的线程少于 corePoolSize 时,即使其他工作线程处于空闲状态,也会创建一个新线程来处理该请求。
maximumPoolSize(非核心线程): 线程池最大运行(包含了核心线程以及非核心线程总数)。
如果运行的线程数多于 corePoolSize 但少于 maximumPoolSize,则仅当队列已满时才会创建新的非核心线程。
keepAliveTime:非核心线程空闲线程的存活时间。
unit:存活时间的单位, 搭配 keepAliveTime 使用。
workQueue:存放任务的队列。
直接提交队列:默认选项 SynchronousQueue,它将任务直接提交给线程而不保存它们。在此期间,如果不存在可用于立即运行任务的线程,则试图把任务加入队列失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
有界队列:当使用有限的 maximumPoolSizes 时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。我的理解是:有界队列其实就是有边界,大小限制,核心线程已经都在使劲工作了,但是任务还是处理不过来,所以放到有界队列中,但是队列是有大小限制的, 当队列满了,那么它会根据maximumPoolSize大小创建非核心线程来处理,而当maximumPoolSize 也达到时设定最大值时,那么轮到拒绝策略工作了。
无界队列:当核心线程满了, 使用无界队列存储(LinkedBlockingQueue没有预定义容量的队列)来存储新任务时,这时候线程的总数不会超过corePoolSize(maxinumPoolSize的值不会改变。)
当大批量任务过来,任务的创建速度远远大于核心线程的消费能力时,无界队列快速增长,内存不多的情况下会出现内存耗尽的问题。
threadFactory:线程池工厂。
handler:拒绝策略。
- 默认策略 AbortPolicy - 处理程序遭到拒绝将抛出运行时 RejectedExecutionException。
- CallerRunsPolicy - 调用execute自身的线程运行任务。这提供了一种简单的反馈控制机制,可以减慢提交新任务的速度。
- DiscardPolicy - 无法执行的任务被简单地丢弃。
- DiscardOldestPolicy中 - 如果执行器没有关闭,则丢弃工作队列头部的任务,然后重试执行(可能再次失败,导致重复此操作。)
暑期编程PK赛 得CSDN机械键盘等精美礼品!


