Java Concurrency - ScheduledThreadPoolExecutor
The Executor framework provides the ThreadPoolExecutor class to execute Callable and Runnable tasks with a pool of threads, which avoid you all the thread creation operations. When you send a task to the executor, it's executed as soon as possible, according to the configuration of the executor. There are used cases when you are not interested in executing a task as soon as possible. You may want to execute a task after a period of time or to execute a task periodically. For these purposes, the Executor framework provides the ScheduledThreadPoolExecutor class.
/**
* This class implements the task of this example. Writes a
* message to the console with the actual date and returns the
* 'Hello, world' string
*/
public class Task implements Callable<String> { /**
* Name of the task
*/
private String name; /**
* Constructor of the class
* @param name Name of the task
*/
public Task(String name) {
this.name = name;
} /**
* Main method of the task. Writes a message to the console with
* the actual date and returns the 'Hello world' string
*/
@Override
public String call() throws Exception {
System.out.printf("%s: Starting at : %s\n", name, new Date());
return "Hello, world";
} } /**
* Main class of the example. Send 5 tasks to an scheduled executor Task 0:
* Delay of 1 second Task 1: Delay of 2 seconds Task 2: Delay of 3 seconds Task
* 3: Delay of 4 seconds Task 4: Delay of 5 seconds
*/
public class Main { /**
* Main method of the example
* @param args
*/
public static void main(String[] args) { // Create a ScheduledThreadPoolExecutor
ScheduledExecutorService executor = (ScheduledExecutorService) Executors.newScheduledThreadPool(1); System.out.printf("Main: Starting at: %s\n", new Date()); // Send the tasks to the executor with the specified delay
for (int i = 0; i < 5; i++) {
Task task = new Task("Task " + i);
executor.schedule(task, i + 1, TimeUnit.SECONDS);
} // Finish the executor
executor.shutdown(); // Waits for the finalization of the executor
try {
executor.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
} // Writes the finalization message
System.out.printf("Core: Ends at: %s\n", new Date());
}
}
The key point of this example is the Main class and the management of ScheduledThreadPoolExecutor. As with class ThreadPoolExecutor, to create a scheduled executor, Java recommends the utilization of the Executors class. In this case, you have to use the newScheduledThreadPool() method. You have passed the number 1 as a parameter to this method. This parameter is the number of threads you want to have in the pool.
To execute a task in this scheduled executor after a period of time, you have to use the schedule() method. This method receives the following three parameters:
- The task you want to execute
- The period of time you want the task to wait before its execution
- The unit of the period of time, specified as a constant of the TimeUnit class
In this case, each task will wait for a number of seconds (TimeUnit.SECONDS) equal to its position in the array of tasks plus one.
If you want to execute a task at a given time, calculate the difference between that date and the current date and use that difference as the delay of the task.
The following snippet shows the output of an execution of this example:
Main: Starting at: Mon Nov 07 16:39:33 CST 2016
Task 0: Starting at : Mon Nov 07 16:39:34 CST 2016
Task 1: Starting at : Mon Nov 07 16:39:35 CST 2016
Task 2: Starting at : Mon Nov 07 16:39:36 CST 2016
Task 3: Starting at : Mon Nov 07 16:39:37 CST 2016
Task 4: Starting at : Mon Nov 07 16:39:38 CST 2016
Core: Ends at: Mon Nov 07 16:39:38 CST 2016
You can see how the tasks start their execution one per second. All the tasks are sent to the executor at the same time, but each one with a delay of 1 second later than the previous task.
You can also use the Runnable interface to implement the tasks, because the schedule() method of the ScheduledThreadPoolExecutor class accepts both types of tasks.
Although the ScheduledThreadPoolExecutor class is a child class of the ThreadPoolExecutor class and, therefore, inherits all its features, Java recommends the utilization of ScheduledThreadPoolExecutor only for scheduled tasks.
Finally, you can configure the behavior of the ScheduledThreadPoolExecutor class when you call the shutdown() method and there are pending tasks waiting for the end of their delay time. The default behavior is that those tasks will be executed despite the finalization of the executor. You can change this behavior using the setExecuteExistingDelayedTasksAfterShutdownPolicy() method of the ScheduledThreadPoolExecutor class. With false, at the time of shutdown(), pending tasks won't get executed.
Running a task in an executor periodically
The Executor framework provides the ThreadPoolExecutor class to execute concurrent tasks using a pool of threads that avoids you all the thread creation operations. When you send a task to the executor, according to its configuration, it executes the task as soon as possible. When it ends, the task is deleted from the executor and, if you want to execute them again, you have to send it again to the executor.
But the Executor framework provides the possibility of executing periodic tasks through the ScheduledThreadPoolExecutor class. In this case, you will learn how to use this functionality of that class to schedule a periodic task.
/**
* This class implements the task of the example. Writes a message to the
* console with the actual date.
* Is used to explain the utilization of an scheduled executor to execute tasks
* periodically
*/
public class Task implements Runnable { /**
* Name of the task
*/
private String name; /**
* Constructor of the class
* @param name the name of the class
*/
public Task(String name) {
this.name = name;
} /**
* Main method of the example. Writes a message to the console with the actual date
*/
@Override
public void run() {
System.out.printf("%s: Executed at: %s\n", name, new Date());
} } /**
* Main class of the example. Send a task to the executor that will execute every
* two seconds. Then, control the remaining time for the next execution of the task
*/
public class Main { /**
* Main method of the class
* @param args
*/
public static void main(String[] args) { // Create a ScheduledThreadPoolExecutor
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
System.out.printf("Main: Starting at: %s\n",new Date()); // Create a new task and sends it to the executor. It will start with a delay of 1 second
// and then it will execute every two seconds
Task task = new Task("Task");
ScheduledFuture<?> result = executor.scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS); // Controlling the execution of tasks
for (int i = 0; i < 10; i++) {
System.out.printf("Main: Delay: %d\n", result.getDelay(TimeUnit.MILLISECONDS));
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
} // Finish the executor
executor.shutdown();
System.out.printf("Main: No more tasks at: %s\n", new Date()); // Verify that the periodic tasks no is in execution after the executor shutdown()
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
} // The example finish
System.out.printf("Main: Finished at: %s\n",new Date());
}
}
When you want to execute a periodic task using the Executor framework, you need a ScheduledExecutorService object. To create it (as with every executor), Java recommends the use of the Executors class. This class works as a factory of executor objects. In this case, you should use the newScheduledThreadPool() method to create a ScheduledExecutorService object. That method receives as a parameter the number of threads of the pool. As you have only one task in this example, you have passed the value 1 as a parameter.
Once you have the executor needed to execute a periodic task, you send the task to the executor. You have used the scheduledAtFixedRate() method. This method accepts four parameters: the task you want to execute periodically, the delay of time until the first execution of the task, the period between two executions, and the time unit of the second and third parameters. It's a constant of the TimeUnit class. The TimeUnit class is an enumeration with the following constants: DAYS, HOURS, MICROSECONDS, MILLISECONDS, MINUTES, NANOSECONDS, and SECONDS.
An important point to consider is that the period between two executions is the period of time between these two executions that begins. If you have a periodic task that takes 5 sceconds to execute and you put a period of 3 seconds, you will have two instances of the task executing at a time.
The method scheduleAtFixedRate() returns a ScheduledFuture object, which extends the Future interface, with methods to work with scheduled tasks. ScheduledFuture is a parameterized interface. In this example, as your task is a Runnable object that is not parameterized, you have to parameterize them with the ? symbol as a parameter.
You have used one method of the ScheduledFuture interface. The getDelay() method returns the time until the next execution of the task. This method receives a TimeUnit constant with the time unit in which you want to receive the results.
The following snippet shows the output of an execution of the example:
Main: Starting at: Mon Nov 07 17:24:22 CST 2016
Main: Delay: 999
Main: Delay: 499
Task: Executed at: Mon Nov 07 17:24:23 CST 2016
Main: Delay: 1998
Main: Delay: 1498
Main: Delay: 998
Main: Delay: 497
Task: Executed at: Mon Nov 07 17:24:25 CST 2016
Main: Delay: 1997
Main: Delay: 1496
Main: Delay: 996
Main: Delay: 496
Task: Executed at: Mon Nov 07 17:24:27 CST 2016
Main: No more tasks at: Mon Nov 07 17:24:27 CST 2016
Main: Finished at: Mon Nov 07 17:24:32 CST 2016
You can see the task executing every 2 seconds (denoted with Task: prefix) and the delay written in the console every 500 milliseconds. That's how long the main thread has been put to sleep. When you shut down the executor, the scheduled task ends its execution and you don't see more messages in the console.
ScheduledThreadPoolExecutor provides other methods to schedule periodic tasks. It is the scheduleWithFixedRate() method. It has the same parameters as the scheduledAtFixedRate() method, but there is a difference worth noticing. In the scheduledAtFixedRate() method, the third parameter determines the period of time between the starting of two executions. In the scheduledWithFixedRate() method, parameter determines the period of time between the end of an execution of the task and the beginning of the next execution.
You can also configure the behavior of an instance of the ScheduledThreadPoolExecutor class with the shutdown() method. The default behavior is that the scheduled tasks finish when you call that method. You can change this behavior using the
setContinueExistingPeriodicTasksAfterShutdownPolicy() method of the ScheduledThreadPoolExecutor class with a true value. The periodic tasks won't finish upon calling the shutdown() method.
Java Concurrency - ScheduledThreadPoolExecutor的更多相关文章
- 深入浅出 Java Concurrency (35): 线程池 part 8 线程池的实现及原理 (3)[转]
线程池任务执行结果 这一节来探讨下线程池中任务执行的结果以及如何阻塞线程.取消任务等等. 1 package info.imxylz.study.concurrency.future;2 3 publ ...
- Java Concurrency in Practice 读书笔记 第十章
粗略看完<Java Concurrency in Practice>这部书,确实是多线程/并发编程的一本好书.里面对各种并发的技术解释得比较透彻,虽然是面向Java的,但很多概念在其他语言 ...
- Java Concurrency - 浅析 CountDownLatch 的用法
The Java concurrency API provides a class that allows one or more threads to wait until a set of ope ...
- Java Concurrency - 浅析 CyclicBarrier 的用法
The Java concurrency API provides a synchronizing utility that allows the synchronization of two or ...
- Java Concurrency - 浅析 Phaser 的用法
One of the most complex and powerful functionalities offered by the Java concurrency API is the abil ...
- Java Concurrency - 线程执行器
Usually, when you develop a simple, concurrent-programming application in Java, you create some Runn ...
- Java Concurrency - Callable & Future
One of the advantages of the Executor framework is that you can run concurrent tasks that return a r ...
- 深入浅出 Java Concurrency (4): 原子操作 part 3 指令重排序与happens-before法则
转: http://www.blogjava.net/xylz/archive/2010/07/03/325168.html 在这个小结里面重点讨论原子操作的原理和设计思想. 由于在下一个章节中会谈到 ...
- 《Java Concurrency》读书笔记,使用JDK并发包构建程序
1. java.util.concurrent概述 JDK5.0以后的版本都引入了高级并发特性,大多数的特性在java.util.concurrent包中,是专门用于多线并发编程的,充分利用了现代多处 ...
随机推荐
- Spring Data Solr教程(翻译)
大多数应用都必须具有某种搜索功能,问题是搜索功能往往是巨大的资源消耗并且它们由于沉重的数据库加载而拖垮你的应用的性能 这就是为什么转移负载到一个外部的搜索服务器是一个不错的主意,Apache Solr ...
- Ioc容器Autofac系列(2)-- asp.net mvc中整合autofac
经过上篇蜻蜓点水的介绍后,本篇通过实例快速上手autofac,展示当asp.net mvc引入了autofac之后会带来什么. 创建Asp.net MVC并引入Autofac 首先,创建一个MVC站点 ...
- CPU与内存(经典问答)
原文:http://www.cnblogs.com/xkfz007/archive/2012/10/08/2715163.html 下面是网上看到的一些关于内存和CPU方面的一些很不错的文章. 整理如 ...
- JS 命名空间 实现方式 收集
一. 对象注册式 // 声明一个全局对象Namespace,用来注册命名空间Namespace = new Object(); // 全局对象仅仅存在register函数,参数为名称空间全路径,如&q ...
- python中List操作
传送门 官方文件地址 list.append(x): 将x加入列表尾部,等价于a[len(a):] = [x] 例: >>> list1=[1,2,3,4] >>> ...
- Python3向网页POST数据
还是以我的网页iciba为例 POST数据到www.selflink.cn/iciba/get0.php获取返回的查询结果 #coding:utf8 import urllib.request imp ...
- Hadoop平台配置总结
hadoop的配置,个人感觉是非常容易出问题.一个原因是要配置的地方多,还有个原因就是集群配置要在几台机器上都配置正确,才能保证配置好hadoop,跑起任务. 经过昨晚加今天上午的折腾,总算成功配好了 ...
- Chrome插件开发 尝试2
在文章1中 尝试了开发chrome一个蛋疼的插件,而且必须要写 一坨令人费解的代码才能只能,今天来次清爽的开发:如图: 这是 "清爽模式" →_→ 我把popup.html与pop ...
- 解决用Eclipse开发Android程序时不能生成R.java的问题
今天我照着Mars老师的视频教程开始学习Android程序开发. 但是,我的Eclipse死活不能生成R.java文件,新建的工程也不行. 然后我百度,百度出来的结果一般是说这样解决: 1.clean ...
- tomcat配置虚拟主机
在眼下,非常多server都是一台server对外能够訪问非常多个javaEE的项目,这样的实现方式就须要在tomcat里面配置虚拟主机了!以下就说说怎样配置虚拟主机: 找到tomcat的安装文件夹, ...