先回顾一下,Runnable 的使用方法。

package demo.knowledgepoints.scheduledtask.run;

/***
* 线程类
*/
public class ThreadTest implements Runnable { public static int ticket = 9; @Override
public void run() {
try {
System.out.println("当前线程:"+Thread.currentThread().getName());
while(true){
synchronized (this) {
Thread.sleep(1000L);
if (this.ticket > 0) {
ticket--;
System.out.println(Thread.currentThread().getName() + ":出售一张票!");
System.out.println("剩余票量:" + ticket);
} else {
System.out.println("没有票了!");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package demo.knowledgepoints.scheduledtask.run;

public class ThreadMemo {
public static void main(String[] args) {
ThreadTest threadTest1 =new ThreadTest();
new Thread(threadTest1).start();
new Thread(threadTest1).start();
}
}

每一个线程的启动,都会占用资源,一个线程5分钟执行一次,一个线程10分钟执行。两个线程分别启动则需要启动两个线程。线程越多需要启动的线程就越多。性能浪费就越大。

于是我们会考虑,5分钟的线程,我们5分钟到了去唤醒一个线程,执行一次,然后再让其睡眠,10分钟的线程也如初,就可以省下同一时间的线程数,线程越多效果越是明显。

正好:java提供了方法:ScheduledExecutorService

我们就根据ScheduledExecutorService来实现一个线程池:

package demo.knowledgepoints.scheduledtask.inf;

import demo.knowledgepoints.scheduledtask.iml.ScheduledTaskTot;

public interface ScheduledService {

    /**
* 添加一个任务
* @author Eric
* @date 16:14 2019/3/12
* @params runnable
* @params taskId
* @params initialDelay 初次等待 毫秒
* @params delay 间隔时间 毫秒(不延迟)
* @throws
* @return boolean
**/
boolean addFixedTask(ScheduledTaskTot scheduledTaskTot); /**
* 添加一个任务
* @author Eric
* @date 16:14 2019/3/12
* @params runnable
* @params taskId
* @params initialDelay 初次等待 毫秒
* @params delay 间隔时间 毫秒(延迟)
* @throws
* @return boolean
**/
boolean addTask(ScheduledTaskTot scheduledTaskTot); /**
* 修改一个任务
* @author Eric
* @date 16:14 2019/3/12
* @params runnable
* @params taskId
* @params initialDelay 初次等待 毫秒
* @params delay 间隔时间 毫秒
* @throws
* @return boolean
**/
boolean updateTask(ScheduledTaskTot scheduledTaskTot) throws InterruptedException; /**
* 移除一个任务
* @author Eric
* @date 16:14 2019/3/12
* @params taskId
* @throws
* @return boolean
**/
boolean remove(String taskId); /**
* 关闭定时任务服务
* @author Eric
* @date 16:14 2019/3/12
* @throws
* @return void
**/
void shutdown(); /**
* 初始化定时任务服务
* @author Eric
* @date 16:15 2019/3/12
* @throws
* @return void
**/
void init() throws Exception;
}
package demo.knowledgepoints.scheduledtask.inf;

public interface TaskServcesInf {

    public void Test1();
public void Test2();
public void Test3();
}
package demo.knowledgepoints.scheduledtask.iml;

import demo.knowledgepoints.scheduledtask.inf.ScheduledService;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; public class ScheduledServiceIml implements ScheduledService { private static ScheduledExecutorService service; private static Map<String, ScheduledFuture> futureMap = new ConcurrentHashMap<>(); @Override
public boolean addFixedTask(ScheduledTaskTot scheduledTaskTot) {
if (futureMap.get(scheduledTaskTot.getTaskId()) != null) {
return false;
}
// 这里将任务放入定时服务中
ScheduledFuture<?> scheduledFuture = service.scheduleAtFixedRate(scheduledTaskTot.getRunnable()
, scheduledTaskTot.getInitialDelay(), scheduledTaskTot.getDelay(), TimeUnit.MILLISECONDS); futureMap.put(scheduledTaskTot.getTaskId(),scheduledFuture);
return true;
} @Override
public boolean addTask(ScheduledTaskTot scheduledTaskTot) {
if (futureMap.get(scheduledTaskTot.getTaskId()) != null) {
return false;
}
// 这里将任务放入定时服务中
ScheduledFuture<?> scheduledFuture = service.scheduleWithFixedDelay(scheduledTaskTot.getRunnable()
, scheduledTaskTot.getInitialDelay(), scheduledTaskTot.getDelay(), TimeUnit.MILLISECONDS); futureMap.put(scheduledTaskTot.getTaskId(),scheduledFuture); return true;
} @Override
public boolean updateTask(ScheduledTaskTot scheduledTaskTot) throws InterruptedException {
if (futureMap.get(scheduledTaskTot.getTaskId()) == null) {
return false;
}
// 先停止
remove(scheduledTaskTot.getTaskId()); // 再添加
addTask(scheduledTaskTot);
return true;
} @Override
public boolean remove(String taskId) {
if (futureMap.get(taskId) == null) {
return false;
}
ScheduledFuture scheduledFuture = futureMap.get(taskId);
scheduledFuture.cancel(false);
futureMap.remove(taskId);
return true;
} @Override
public void shutdown() {
service.shutdown();
} @Override
public void init() throws Exception {
service = Executors.newScheduledThreadPool(8);
}
}
package demo.knowledgepoints.scheduledtask.iml;

import demo.untils.StringUntil;
import demo.untils.TimeUtil; import java.lang.reflect.Method; public class ScheduledTaskTot { /** 需要执行方法的线程 */
Runnable runnable;
/** 唯一的id用于增删改 */
String taskId;
/** 定时任务需要执行的方法类 */
String className;
/** 定时任务需要执行的方法 */
String method;
/** 首次执行等待时间 */
long initialDelay;
/** 间隔时间 */
long delay; /**
* 创建一个需要定时的任务
* @param taskId
* @param className
* @param method
* @param initialDelay
* @param delay
* @param beginTime(执行开始时间)
* @param endTime(执行结束时间)
*/
public ScheduledTaskTot(String taskId, String className, String method, long initialDelay, long delay, String beginTime, String endTime) {
this.taskId = taskId;
this.className = className;
this.method = method;
this.initialDelay = initialDelay;
this.delay = delay;
// 在创建实例的时候,初始化线程类,通过反射获取要执行的类与方法,目前没有加参数,大家可以自行扩展
runnable = () -> {
System.out.println("---------------------------------");
try {
//在beginTime 到 endTime 之间才执行。
if(StringUntil.isNotBlank(beginTime) && StringUntil.isNotBlank(endTime)){
if(TimeUtil.getTimeMillis(beginTime) - System.currentTimeMillis() >= 0 && TimeUtil.getTimeMillis(endTime) - System.currentTimeMillis() <= 0){
Class<?> cls = Class.forName(className);
Method method1 = cls.getMethod(method);
method1.invoke(cls.newInstance(),null);
}
}else{
Class<?> cls = Class.forName(className);
Method method1 = cls.getMethod(method);
method1.invoke(cls.newInstance(),null);
}
} catch (Exception e) {
e.printStackTrace();
}
};
} public Runnable getRunnable() {
return runnable;
} public void setRunnable(Runnable runnable) {
this.runnable = runnable;
} public String getTaskId() {
return taskId;
} public void setTaskId(String taskId) {
this.taskId = taskId;
} public String getClassName() {
return className;
} public void setClassName(String className) {
this.className = className;
} public String getMethod() {
return method;
} public void setMethod(String method) {
this.method = method;
} public long getInitialDelay() {
return initialDelay;
} public void setInitialDelay(long initialDelay) {
this.initialDelay = initialDelay;
} public long getDelay() {
return delay;
} public void setDelay(long delay) {
this.delay = delay;
}
}
package demo.knowledgepoints.scheduledtask.iml;

import demo.knowledgepoints.scheduledtask.inf.TaskServcesInf;

public class TaskServcesIml implements TaskServcesInf {

    public void Test1(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Test1------------------------");
}
public void Test2(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Test2------------------------");
} public void Test3(){
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Test3------------------------");
}
}
package demo.knowledgepoints.scheduledtask.iml;

public class ScheduledServiceTest {

    public static void main(String[] args) {
ScheduledServiceIml scheduledServiceIml = new ScheduledServiceIml();
try {
scheduledServiceIml.init();
scheduledServiceIml.addTask(new ScheduledTaskTot("T0001","demo.knowledgepoints.scheduledtask.iml.TaskServcesIml","Test1",1000L,5000L,null,null));
scheduledServiceIml.addTask(new ScheduledTaskTot("T0002","demo.knowledgepoints.scheduledtask.iml.TaskServcesIml","Test2",1000L,5000L,null,null));
scheduledServiceIml.addTask(new ScheduledTaskTot("T0003","demo.knowledgepoints.scheduledtask.iml.TaskServcesIml","Test3",1000L,5000L,null,null));
} catch (Exception e) {
e.printStackTrace();
}
}
}

输出结果:

参考资料:https://blog.csdn.net/money9sun/article/details/88575704?tdsourcetag=s_pctim_aiomsg

如有疑问请留言,每一个都会及时回复。


《Java知识应用》Java-线程池(ScheduledExecutorService)的更多相关文章

  1. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

  2. Java多线程-新特性-线程池

    Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利.为了编写高效稳定可靠的多线程程序 ...

  3. 深入理解Java自带的线程池和缓冲队列

    前言 线程池是什么 线程池的概念是初始化线程池时在池中创建空闲的线程,一但有工作任务,可直接使用线程池中的线程进行执行工作任务,任务执行完成后又返回线程池中成为空闲线程.使用线程池可以减少线程的创建和 ...

  4. Java:多线程,线程池,用Executors静态工厂生成常用线程池

    一: newSingleThreadExecutor 创建一个单线程的线程池,以无界队列方式运行.这个线程池只有一个线程在工作(如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它.)此线程池 ...

  5. 【转】线程池体系介绍及从阿里Java开发手册学习线程池的正确创建方法

    jdk1.7中java.util.concurrent.Executor线程池体系介绍 java.util.concurrent.Executor : 负责线程的使用与调度的根接口  |–Execut ...

  6. java高并发之线程池

    Java高并发之线程池详解   线程池优势 在业务场景中, 如果一个对象创建销毁开销比较大, 那么此时建议池化对象进行管理. 例如线程, jdbc连接等等, 在高并发场景中, 如果可以复用之前销毁的对 ...

  7. Java并发编程:线程池ThreadPoolExecutor

    多线程的程序的确能发挥多核处理器的性能.虽然与进程相比,线程轻量化了很多,但是其创建和关闭同样需要花费时间.而且线程多了以后,也会抢占内存资源.如果不对线程加以管理的话,是一个非常大的隐患.而线程池的 ...

  8. Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  9. Java多线程系列--“JUC线程池”06之 Callable和Future

    概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...

  10. Java多线程系列--“JUC线程池”02之 线程池原理(一)

    概要 在上一章"Java多线程系列--“JUC线程池”01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析Th ...

随机推荐

  1. Mac安装和卸载Mysql

    目录 一.安装 二.环境变量 2.1 MySQL服务的启停和状态的查看 三.启动 四.初始化设置 4.1 退出sql界面 五.配置 5.1 检测修改结果 一.安装 第一步:打开网址,https://w ...

  2. 20191010-9 alpha week 1/2 Scrum立会报告+燃尽图 07

    此作业要求参见https://edu.cnblogs.com/campus/nenu/2019fall/homework/8752 一.小组情况 队名:扛把子 组长:迟俊文 组员:宋晓丽 梁梦瑶 韩昊 ...

  3. Oracle的高水位线

    一.什么是水位线 所有的oracle段都会有一个在段内容纳数据的上线,把这个上限成为“high water mark”,这是一个标记,用来说明已经有多少没有使用的数据块分配给这个段,原则上high w ...

  4. 折腾笔记-计蒜客t1156AC记

    欢迎查看原题地址 此题思路(最初版): 暴力,得出最相近的,1000ms呢,除非数据超大,否则不超时. 说明: 爆搜,搜出结果,时间复杂度基本 $O(n^2)$ 注:本文所有时间(与空间)复杂度仅为估 ...

  5. python内置的进制转换方法

    python进制转换方法总结表: ↓ 2进制 8进制 10进制 16进制 2进制 - bin(int(x, 8)) bin(int(x, 10)) bin(int(x, 16)) 8进制 oct(in ...

  6. linux磁盘分区三步走

    为了便于理解硬盘的物理结构 ,可将硬盘看作一个圆,它是坚硬金属材料制成的涂以磁性介质的盘片,不同容量硬盘的盘片数不等.每个盘有两面,都可记录信息.要了解硬盘的物理结构,需要弄懂磁道.扇区.柱面.簇等几 ...

  7. 为什么坚果云Markdown值得使用?

    值得使用说明是被认为有价值的,值得有两种意思的解释:1.有价值,有意义:2.价钱合适,合算:那么坚果云Markdown是否是人们值得使用的呢?下面就来看看坚果云Markdown到底是什么?为什么值得使 ...

  8. Spring Boot整合Mybatis报错InstantiationException: tk.mybatis.mapper.provider.base.BaseSelectProvider

    Spring Boot整合Mybatis时一直报错 后来发现原来主配置类上的MapperScan导错了包 由于我使用了通用Mapper,所以应该导入通用mapper这个包

  9. 转帖:30多条mysql数据库优化方法,千万级数据库记录查询轻松解决

    地址:http://www.ihref.com/read-16422.html

  10. bs4-爬取小说

    bs4 bs4有两种运行方式一种是处理本地资源,一种是处理网络资源 本地 from bs4 import BeautifulSoup if __name__ == '__main__': fr = o ...