Java线程池入门必备
线程池
一. 线程池的简介
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-1
pool-1-thread-2
pool-1-thread-1
pool-1-thread-2
pool-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-1
pool-1-thread-2
pool-1-thread-4
pool-1-thread-3
pool-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-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-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-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-2
pool-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
每次执行时间为上一次任务结束起向后推一个时间间隔,即每次执行时间为:initialDela
y, 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中的应用. 一.大小固定的线程池——Executors.newFixedThreadPool() 下面咱们明确两个类: ...
- Java线程池入门
序 为什么要用线程池?什么情况下才会用到线程池? 并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 因此 ...
- 面试必备:Java线程池解析
前言 掌握线程池是后端程序员的基本要求,相信大家求职面试过程中,几乎都会被问到有关于线程池的问题.我在网上搜集了几道经典的线程池面试题,并以此为切入点,谈谈我对线程池的理解.如果有哪里理解不正确,非常 ...
- 干货,阿里P8浅谈对java线程池的理解(面试必备)
线程池的概念 线程池由任务队列和工作线程组成,它可以重用线程来避免线程创建的开销,在任务过多时通过排队避免创建过多线程来减少系统资源消耗和竞争,确保任务有序完成:ThreadPoolExecutor ...
- 深入浅出Java线程池:源码篇
前言 在上一篇文章深入浅出Java线程池:理论篇中,已经介绍了什么是线程池以及基本的使用.(本来写作的思路是使用篇,但经网友建议后,感觉改为理论篇会更加合适).本文则深入线程池的源码,主要是介绍Thr ...
- Java 线程池框架核心代码分析--转
原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...
- Java线程池使用说明
Java线程池使用说明 转自:http://blog.csdn.net/sd0902/article/details/8395677 一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极 ...
- (转载)JAVA线程池管理
平时的开发中线程是个少不了的东西,比如tomcat里的servlet就是线程,没有线程我们如何提供多用户访问呢?不过很多刚开始接触线程的开发攻城师却在这个上面吃了不少苦头.怎么做一套简便的线程开发模式 ...
- Java线程池的那些事
熟悉java多线程的朋友一定十分了解java的线程池,jdk中的核心实现类为java.util.concurrent.ThreadPoolExecutor.大家可能了解到它的原理,甚至看过它的源码:但 ...
随机推荐
- 蓝桥杯-逆波兰表达式-java
/* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...
- grunt轻松入门
项目目录,js源文件 gruntest Gruntfile.js package.json -- js ext community_plugin.js glogin_frm_cover.js iLog ...
- xmlplus 组件设计系列之十 - 网格(DataGrid)
这一章我们要实现是一个网格组件,该组件除了最基本的数据展示功能外,还提供排序以及数据过滤功能. 数据源 为了测试我们即将编写好网格组件,我们采用如下格式的数据源.此数据源包含两部分的内容,分别是表头数 ...
- Spring Boot 学习笔记
参考资料 http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/ Spring Boot简介 Spring Boot使 ...
- Python学习之路-Day1-Python基础
学习python的过程: 在茫茫的编程语言中我选择了python,因为感觉python很强大,能用到很多领域.我自己也学过一些编程语言,比如:C,java,php,html,css等.但是我感觉自己都 ...
- poj2481 Cows 树状数组
题目链接:http://poj.org/problem?id=2481 解题思路: 这道题对每组数据进行查询,是树状数组的应用.对于二维的树状数组, 首先想到排序.现在对输入的数据按右值从大到小排序, ...
- Spring AOP的切入点表达式
在spring Aop中要使用AspectJ的切点表达式语言来定义切点.Spring仅仅支持AspectJ切点指示器的一个子集.下表列出了Spring AOP所支持的AspectJ切点指示器. 在Sp ...
- 使用 jQuery.Pin 垂直滚动时固定导航
ZKEACMS的导航默认是不能固定的,随着页面的滚动而滚动,为了有更好的用户体验,当页面往下滚动时,可以将导航固定在顶端,这样方便用户点击. jQuery Pin 借助jQuery的一个插件 jQue ...
- javaWeb学习总结(8)- jsp指令(3)
一.JSP指令简介 一.JSP指令简介 JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分. 在JSP 2.0规范中共定 ...
- A function to help graphical model checks of lm and ANOVA(转)
As always a more colourful version of this post is available on rpubs. Even if LM are very simple mo ...