Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去,欢迎建议和指导):github.com/Snailclimb/…html
Java并发编程指南专栏java
分布式系统的经典基础理论git
面试中关于Java虚拟机(jvm)的问题看这篇就够了github
思惟导图源文件+思惟导图软件关注微信公众号:“Java面试通关手册” 回复关键字:“Java多线程” 免费领取。面试
线程池提供了一种限制和管理资源(包括执行一个任务)。 每一个线程池还维护一些基本统计信息,例如已完成任务的数量。 这里借用《Java并发编程的艺术》提到的来讲一下使用线程池的好处:编程
Executor 框架是Java5以后引进的,在Java 5以后,经过 Executor 来启动线程比使用 Thread 的 start 方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免 this 逃逸问题。小程序
补充:this逃逸是指在构造函数返回以前其余线程就持有该对象的引用. 调用还没有构造彻底的对象的方法可能引起使人疑惑的错误。bash
执行任务须要实现的Runnable接口或Callable接口。 Runnable接口或Callable接口实现类均可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor执行。服务器
二者的区别:
Runnable接口不会返回结果可是Callable接口能够返回结果。后面介绍Executors类的一些方法的时候会介绍到二者的相互转换。
以下图所示,包括任务执行机制的核心接口Executor ,以及继承自Executor 接口的ExecutorService接口。ScheduledThreadPoolExecutor和ThreadPoolExecutor这两个关键类实现了ExecutorService接口。
注意: 经过查看ScheduledThreadPoolExecutor源代码咱们发现ScheduledThreadPoolExecutor其实是继承了ThreadPoolExecutor并实现了ScheduledExecutorService ,而ScheduledExecutorService又实现了ExecutorService,正如咱们下面给出的类关系图显示的同样。
ThreadPoolExecutor类描述:
//AbstractExecutorService实现了ExecutorService接口
public class ThreadPoolExecutor extends AbstractExecutorService 复制代码
ScheduledThreadPoolExecutor类描述:
//ScheduledExecutorService实现了ExecutorService接口
public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService 复制代码
Future接口以及Future接口的实现类FutureTask类。 当咱们把Runnable接口或Callable接口的实现类提交(调用submit方法)给ThreadPoolExecutor或ScheduledThreadPoolExecutor时,会返回一个FutureTask对象。
咱们以AbstractExecutorService接口中的一个submit方法为例子来看看源代码:
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
复制代码
上面方法调用的newTaskFor方法返回了一个FutureTask对象。
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
复制代码
主线程首先要建立实现Runnable或者Callable接口的任务对象。 备注: 工具类Executors能够实现Runnable对象和Callable对象之间的相互转换。(Executors.callable(Runnable task)或Executors.callable(Runnable task,Object resule))。
而后能够把建立完成的Runnable对象直接交给ExecutorService执行(ExecutorService.execute(Runnable command));或者也能够把Runnable对象或Callable对象提交给ExecutorService执行(ExecutorService.submit(Runnable task)或ExecutorService.submit(Callable task))。
执行execute()方法和submit()方法的区别是什么呢? 1)execute()方法用于提交不须要返回值的任务,因此没法判断任务是否被线程池执行成功与否; 2)submit()方法用于提交须要返回值的任务。线程池会返回一个future类型的对象,经过这个future对象能够判断任务是否执行成功,而且能够经过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后当即返回,这时候有可能任务没有执行完。
若是执行ExecutorService.submit(…),ExecutorService将返回一个实现Future接口的对象(咱们刚刚也提到过了执行execute()方法和submit()方法的区别,到目前为止的JDK中,返回的是FutureTask对象)。因为FutureTask实现了Runnable,程序员也能够建立FutureTask,而后直接交给ExecutorService执行。
最后,主线程能够执行FutureTask.get()方法来等待任务执行完成。主线程也能够执行FutureTask.cancel(boolean mayInterruptIfRunning)来取消此任务的执行。
线程池实现类ThreadPoolExecutor是Executor 框架最核心的类,先来看一下这个类中比较重要的四个属性
咱们看最长的那个,其他三个都是在这个构造方法的基础上产生(给定某些默认参数的构造方法)
/** * 用给定的初始参数建立一个新的ThreadPoolExecutor。 * @param keepAliveTime 当线程池中的线程数量大于corePoolSize的时候,若是这时没有新的任务提交, *核心线程外的线程不会当即销毁,而是会等待,直到等待的时间超过了keepAliveTime; * @param unit keepAliveTime参数的时间单位 * @param workQueue 等待队列,当任务提交时,若是线程池中的线程数量大于等于corePoolSize的时候,把该任务封装成一个Worker对象放入等待队列; * * @param threadFactory 执行者建立新线程时使用的工厂 * @param handler RejectedExecutionHandler类型的变量,表示线程池的饱和策略。 * 若是阻塞队列满了而且没有空闲的线程,这时若是继续提交任务,就须要采起一种策略处理该任务。 * 线程池提供了4种策略: 1.AbortPolicy:直接抛出异常,这是默认策略; 2.CallerRunsPolicy:用调用者所在的线程来执行任务; 3.DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务; 4.DiscardPolicy:直接丢弃任务; */
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
复制代码
方式一:经过构造方法实现(官方API文档并不推荐,因此建议使用第二种方式)
对应Executors工具类中的方法如图所示:
FixedThreadPool被称为可重用固定线程数的线程池。经过Executors类中的相关源代码来看一下相关实现:
/** * 建立一个可重用固定数量线程的线程池 *在任什么时候候至多有n个线程处于活动状态 *若是在全部线程处于活动状态时提交其余任务,则它们将在队列中等待, *直到线程可用。 若是任何线程在关闭以前的执行期间因为失败而终止, *若是须要执行后续任务,则一个新的线程将取代它。池中的线程将一直存在 *知道调用shutdown方法 * @param nThreads 线程池中的线程数 * @param threadFactory 建立新线程时使用的factory * @return 新建立的线程池 * @throws NullPointerException 若是threadFactory为null * @throws IllegalArgumentException if {@code nThreads <= 0} */
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
复制代码
另外还有一个FixedThreadPool的实现方法,和上面的相似,因此这里很少作阐述:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
复制代码
从上面源代码能够看出新建立的FixedThreadPool的corePoolSize和maximumPoolSize都被设置为nThreads。 FixedThreadPool的execute()方法运行示意图(该图片来源:《Java并发编程的艺术》):
上图说明:
FixedThreadPool使用无界队列 LinkedBlockingQueue(队列的容量为Intger.MAX_VALUE)做为线程池的工做队列会对线程池带来以下影响:
SingleThreadExecutor是使用单个worker线程的Executor。下面看看SingleThreadExecutor的实现:
/** *建立使用单个worker线程运行无界队列的Executor *并使用提供的ThreadFactory在须要时建立新线程 * * @param threadFactory 建立新线程时使用的factory * * @return 新建立的单线程Executor * @throws NullPointerException 若是ThreadFactory为空 */
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
复制代码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
复制代码
从上面源代码能够看出新建立的SingleThreadExecutor的corePoolSize和maximumPoolSize都被设置为1.其余参数和FixedThreadPool相同。SingleThreadExecutor使用无界队列LinkedBlockingQueue做为线程池的工做队列(队列的容量为Intger.MAX_VALUE)。SingleThreadExecutor使用无界队列做为线程池的工做队列会对线程池带来的影响与FixedThreadPool相同。
SingleThreadExecutor的运行示意图(该图片来源:《Java并发编程的艺术》):
上图说明;
CachedThreadPool是一个会根据须要建立新线程的线程池。下面经过源码来看看 CachedThreadPool的实现:
/** * 建立一个线程池,根据须要建立新线程,但会在先前构建的线程可用时重用它, *并在须要时使用提供的ThreadFactory建立新线程。 * @param threadFactory 建立新线程使用的factory * @return 新建立的线程池 * @throws NullPointerException 若是threadFactory为空 */
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
复制代码
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
复制代码
CachedThreadPool的corePoolSize被设置为空(0),maximumPoolSize被设置为Integer.MAX.VALUE,即它是无界的,这也就意味着若是主线程提交任务的速度高于maximumPool中线程处理任务的速度时,CachedThreadPool会不断建立新的线程。极端状况下,这样会致使耗尽cpu和内存资源。
CachedThreadPool的execute()方法的执行示意图(该图片来源:《Java并发编程的艺术》):
上图说明:
首先建立一个Runnable接口的实现类(固然也能够是Callable接口,咱们上面也说了二者的区别是:Runnable接口不会返回结果可是Callable接口能够返回结果。后面介绍Executors类的一些方法的时候会介绍到二者的相互转换。)
import java.util.Date;
/** * 这是一个简单的Runnable类,须要大约5秒钟来执行其任务。 */
public class WorkerThread implements Runnable {
private String command;
public WorkerThread(String s) {
this.command = s;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Start. Time = " + new Date());
processCommand();
System.out.println(Thread.currentThread().getName() + " End. Time = " + new Date());
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return this.command;
}
}
复制代码
编写测试程序,咱们这里以FixedThreadPool为例子
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorDemo {
public static void main(String[] args) {
//建立一个FixedThreadPool对象
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
//建立WorkerThread对象(WorkerThread类实现了Runnable 接口)
Runnable worker = new WorkerThread("" + i);
//执行Runnable
executor.execute(worker);
}
//终止线程池
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("Finished all threads");
}
}
复制代码
输出示例:
pool-1-thread-5 Start. Time = Thu May 31 10:22:52 CST 2018
pool-1-thread-3 Start. Time = Thu May 31 10:22:52 CST 2018
pool-1-thread-2 Start. Time = Thu May 31 10:22:52 CST 2018
pool-1-thread-4 Start. Time = Thu May 31 10:22:52 CST 2018
pool-1-thread-1 Start. Time = Thu May 31 10:22:52 CST 2018
pool-1-thread-4 End. Time = Thu May 31 10:22:57 CST 2018
pool-1-thread-1 End. Time = Thu May 31 10:22:57 CST 2018
pool-1-thread-2 End. Time = Thu May 31 10:22:57 CST 2018
pool-1-thread-5 End. Time = Thu May 31 10:22:57 CST 2018
pool-1-thread-3 End. Time = Thu May 31 10:22:57 CST 2018
pool-1-thread-5 Start. Time = Thu May 31 10:22:57 CST 2018
pool-1-thread-2 Start. Time = Thu May 31 10:22:57 CST 2018
pool-1-thread-1 Start. Time = Thu May 31 10:22:57 CST 2018
pool-1-thread-4 Start. Time = Thu May 31 10:22:57 CST 2018
pool-1-thread-3 Start. Time = Thu May 31 10:22:57 CST 2018
pool-1-thread-5 End. Time = Thu May 31 10:23:02 CST 2018
pool-1-thread-1 End. Time = Thu May 31 10:23:02 CST 2018
pool-1-thread-2 End. Time = Thu May 31 10:23:02 CST 2018
pool-1-thread-3 End. Time = Thu May 31 10:23:02 CST 2018
pool-1-thread-4 End. Time = Thu May 31 10:23:02 CST 2018
Finished all threads
复制代码
shutdown()方法代表关闭已在Executor上调用,所以不会再向DelayedPool添加任何其余任务(由ScheduledThreadPoolExecutor类在内部使用)。 可是,已经在队列中提交的任务将被容许完成。 另外一方面,shutdownNow()方法试图终止当前正在运行的任务,并中止处理排队的任务并返回正在等待执行的List。 ####3.7.3 isTerminated() Vs isShutdown() isShutdown()表示执行程序正在关闭,但并不是全部任务都已完成执行。 另外一方面,isShutdown()表示全部线程都已完成执行。
ScheduledThreadPoolExecutor主要用来在给定的延迟后运行任务,或者按期执行任务。
ScheduledThreadPoolExecutor使用的任务队列DelayQueue封装了一个PriorityQueue,PriorityQueue会对队列中的任务进行排序,执行所需时间短的放在前面先被执行(ScheduledFutureTask的time变量小的先执行),若是执行所需时间相同则先提交的任务将被先执行(ScheduledFutureTask的squenceNumber变量小的先执行)。
ScheduledThreadPoolExecutor和Timer的比较:
综上,在JDK1.5以后,你没有理由再使用Timer进行任务调度了。
备注: Quartz是一个由java编写的任务调度库,由OpenSymphony组织开源出来。在实际项目开发中使用Quartz的仍是居多,比较推荐使用Quartz。由于Quartz理论上可以同时对上万个任务进行调度,拥有丰富的功能特性,包括任务调度、任务持久化、可集群化、插件等等。
ScheduledThreadPoolExecutor的执行主要分为两大部分:
ScheduledThreadPoolExecutor为了实现周期性的执行任务,对ThreadPoolExecutor作了以下修改:
建立一个简单的实现Runnable接口的类(咱们上面的例子已经实现过)
测试程序使用ScheduledExecutorService和ScheduledThreadPoolExecutor实现的java调度。
/** * 使用ScheduledExecutorService和ScheduledThreadPoolExecutor实现的java调度程序示例程序。 */
public class ScheduledThreadPoolDemo {
public static void main(String[] args) throws InterruptedException {
//建立一个ScheduledThreadPoolExecutor对象
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
//计划在某段时间后运行
System.out.println("Current Time = "+new Date());
for(int i=0; i<3; i++){
Thread.sleep(1000);
WorkerThread worker = new WorkerThread("do heavy processing");
//建立并执行在给定延迟后启用的单次操做。
scheduledThreadPool.schedule(worker, 10, TimeUnit.SECONDS);
}
//添加一些延迟让调度程序产生一些线程
Thread.sleep(30000);
System.out.println("Current Time = "+new Date());
//关闭线程池
scheduledThreadPool.shutdown();
while(!scheduledThreadPool.isTerminated()){
//等待全部任务完成
}
System.out.println("Finished all threads");
}
}
复制代码
运行结果:
Current Time = Wed May 30 17:11:16 CST 2018
pool-1-thread-1 Start. Time = Wed May 30 17:11:27 CST 2018
pool-1-thread-2 Start. Time = Wed May 30 17:11:28 CST 2018
pool-1-thread-3 Start. Time = Wed May 30 17:11:29 CST 2018
pool-1-thread-1 End. Time = Wed May 30 17:11:32 CST 2018
pool-1-thread-2 End. Time = Wed May 30 17:11:33 CST 2018
pool-1-thread-3 End. Time = Wed May 30 17:11:34 CST 2018
Current Time = Wed May 30 17:11:49 CST 2018
Finished all threads
复制代码
咱们可使用ScheduledExecutorService scheduleAtFixedRate方法来安排任务在初始延迟后运行,而后在给定的时间段内运行。
时间段是从池中第一个线程的开始,所以若是您将period指定为1秒而且线程运行5秒,那么只要第一个工做线程完成执行,下一个线程就会开始执行。
for (int i = 0; i < 3; i++) {
Thread.sleep(1000);
WorkerThread worker = new WorkerThread("do heavy processing");
// schedule task to execute at fixed rate
scheduledThreadPool.scheduleAtFixedRate(worker, 0, 10,
TimeUnit.SECONDS);
}
复制代码
输出示例:
Current Time = Wed May 30 17:47:09 CST 2018
pool-1-thread-1 Start. Time = Wed May 30 17:47:10 CST 2018
pool-1-thread-2 Start. Time = Wed May 30 17:47:11 CST 2018
pool-1-thread-3 Start. Time = Wed May 30 17:47:12 CST 2018
pool-1-thread-1 End. Time = Wed May 30 17:47:15 CST 2018
pool-1-thread-2 End. Time = Wed May 30 17:47:16 CST 2018
pool-1-thread-3 End. Time = Wed May 30 17:47:17 CST 2018
pool-1-thread-1 Start. Time = Wed May 30 17:47:20 CST 2018
pool-1-thread-4 Start. Time = Wed May 30 17:47:21 CST 2018
pool-1-thread-2 Start. Time = Wed May 30 17:47:22 CST 2018
pool-1-thread-1 End. Time = Wed May 30 17:47:25 CST 2018
pool-1-thread-4 End. Time = Wed May 30 17:47:26 CST 2018
pool-1-thread-2 End. Time = Wed May 30 17:47:27 CST 2018
pool-1-thread-1 Start. Time = Wed May 30 17:47:30 CST 2018
pool-1-thread-3 Start. Time = Wed May 30 17:47:31 CST 2018
pool-1-thread-5 Start. Time = Wed May 30 17:47:32 CST 2018
pool-1-thread-1 End. Time = Wed May 30 17:47:35 CST 2018
pool-1-thread-3 End. Time = Wed May 30 17:47:36 CST 2018
pool-1-thread-5 End. Time = Wed May 30 17:47:37 CST 2018
pool-1-thread-1 Start. Time = Wed May 30 17:47:40 CST 2018
pool-1-thread-2 Start. Time = Wed May 30 17:47:41 CST 2018
Current Time = Wed May 30 17:47:42 CST 2018
pool-1-thread-1 End. Time = Wed May 30 17:47:45 CST 2018
pool-1-thread-2 End. Time = Wed May 30 17:47:46 CST 2018
Finished all threads
Process finished with exit code 0
复制代码
ScheduledExecutorService scheduleWithFixedDelay方法可用于以初始延迟启动周期性执行,而后以给定延迟执行。 延迟时间是线程完成执行的时间。
for (int i = 0; i < 3; i++) {
Thread.sleep(1000);
WorkerThread worker = new WorkerThread("do heavy processing");
scheduledThreadPool.scheduleWithFixedDelay(worker, 0, 1,
TimeUnit.SECONDS);
}
复制代码
输出示例:
Current Time = Wed May 30 17:58:09 CST 2018
pool-1-thread-1 Start. Time = Wed May 30 17:58:10 CST 2018
pool-1-thread-2 Start. Time = Wed May 30 17:58:11 CST 2018
pool-1-thread-3 Start. Time = Wed May 30 17:58:12 CST 2018
pool-1-thread-1 End. Time = Wed May 30 17:58:15 CST 2018
pool-1-thread-2 End. Time = Wed May 30 17:58:16 CST 2018
pool-1-thread-1 Start. Time = Wed May 30 17:58:16 CST 2018
pool-1-thread-3 End. Time = Wed May 30 17:58:17 CST 2018
pool-1-thread-4 Start. Time = Wed May 30 17:58:17 CST 2018
pool-1-thread-2 Start. Time = Wed May 30 17:58:18 CST 2018
pool-1-thread-1 End. Time = Wed May 30 17:58:21 CST 2018
pool-1-thread-1 Start. Time = Wed May 30 17:58:22 CST 2018
pool-1-thread-4 End. Time = Wed May 30 17:58:22 CST 2018
pool-1-thread-2 End. Time = Wed May 30 17:58:23 CST 2018
pool-1-thread-2 Start. Time = Wed May 30 17:58:23 CST 2018
pool-1-thread-4 Start. Time = Wed May 30 17:58:24 CST 2018
pool-1-thread-1 End. Time = Wed May 30 17:58:27 CST 2018
pool-1-thread-2 End. Time = Wed May 30 17:58:28 CST 2018
pool-1-thread-1 Start. Time = Wed May 30 17:58:28 CST 2018
pool-1-thread-2 Start. Time = Wed May 30 17:58:29 CST 2018
pool-1-thread-4 End. Time = Wed May 30 17:58:29 CST 2018
pool-1-thread-4 Start. Time = Wed May 30 17:58:30 CST 2018
pool-1-thread-1 End. Time = Wed May 30 17:58:33 CST 2018
pool-1-thread-2 End. Time = Wed May 30 17:58:34 CST 2018
pool-1-thread-1 Start. Time = Wed May 30 17:58:34 CST 2018
pool-1-thread-2 Start. Time = Wed May 30 17:58:35 CST 2018
pool-1-thread-4 End. Time = Wed May 30 17:58:35 CST 2018
pool-1-thread-4 Start. Time = Wed May 30 17:58:36 CST 2018
pool-1-thread-1 End. Time = Wed May 30 17:58:39 CST 2018
pool-1-thread-2 End. Time = Wed May 30 17:58:40 CST 2018
pool-1-thread-5 Start. Time = Wed May 30 17:58:40 CST 2018
pool-1-thread-4 End. Time = Wed May 30 17:58:41 CST 2018
pool-1-thread-2 Start. Time = Wed May 30 17:58:41 CST 2018
Current Time = Wed May 30 17:58:42 CST 2018
pool-1-thread-5 End. Time = Wed May 30 17:58:45 CST 2018
pool-1-thread-2 End. Time = Wed May 30 17:58:46 CST 2018
Finished all threads
复制代码
scheduleAtFixedRate(...)将延迟视为两个任务开始之间的差别(即按期调用) scheduleWithFixedDelay(...)将延迟视为一个任务结束与下一个任务开始之间的差别
scheduleAtFixedRate(): 建立并执行在给定的初始延迟以后,随后以给定的时间段首先启用的周期性动做; 那就是执行将在initialDelay以后开始,而后initialDelay+period ,而后是initialDelay + 2 * period ,等等。 若是任务的执行遇到异常,则后续的执行被抑制。 不然,任务将仅经过取消或终止执行人终止。 若是任务执行时间比其周期长,则后续执行可能会迟到,但不会同时执行。 scheduleWithFixedDelay() : 建立并执行在给定的初始延迟以后首先启用的按期动做,随后在一个执行的终止和下一个执行的开始之间给定的延迟。 若是任务的执行遇到异常,则后续的执行被抑制。 不然,任务将仅经过取消或终止执行终止。
FixedThreadPool: 适用于为了知足资源管理需求,而须要限制当前线程数量的应用场景。它适用于负载比较重的服务器;
SingleThreadExecutor: 适用于须要保证顺序地执行各个任务而且在任意时间点,不会有多个线程是活动的应用场景。
CachedThreadPool: 适用于执行不少的短时间异步任务的小程序,或者是负载较轻的服务器;
ScheduledThreadPoolExecutor: 适用于须要多个后台执行周期任务,同时为了知足资源管理需求而须要限制后台线程的数量的应用场景,
SingleThreadScheduledExecutor: 适用于须要单个后台线程执行周期任务,同时保证顺序地执行各个任务的应用场景。
本节只是简单的介绍了一下使用线程池的好处,而后花了大量篇幅介绍Executor 框架。详细介绍了Executor 框架中ThreadPoolExecutor和ScheduledThreadPoolExecutor,而且经过实例详细讲解了ScheduledThreadPoolExecutor的使用。对于FutureTask 只是粗略带过,由于篇幅问题,并无深究它的原理,后面的文章会进行补充。这一篇文章只是大概带你们过一下线程池的基本概览,深刻讲解的地方不是不少,后续会经过源码深刻研究其中比较重要的一些知识点。
最后,就是这两周要考试了,会抽点时间出来简单应付一下学校考试了。而后,就是写这篇多线程的文章废了好多好多时间。一直不知从何写起。
《Java并发编程的艺术》
Java Scheduler ScheduledExecutorService ScheduledThreadPoolExecutor Example
java.util.concurrent.ScheduledThreadPoolExecutor Example
ThreadPoolExecutor – Java Thread Pool Example
我是Snailclimb,一个以架构师为5年以内目标的小小白。 欢迎关注个人微信公众号:"Java面试通关手册"(一个有温度的微信公众号,期待与你共同进步~~~坚持原创,分享美文,分享各类Java学习资源)
最后,就是使用阿里云服务器一段时间后,感受阿里云真的很不错,就申请作了阿里云大使,而后这是个人优惠券地址.