JAVA多线程提高一:传统线程技术&传统定时器Timer
前面我们已经对多线程的基础知识有了一定的了解,那么接下来我们将要对多线程进一步深入的学习;但在学习之前我们还是要对传统的技术进行一次回顾,本章我们回顾的则是:传统线程技术和传统的定时器实现.
一、传统线程技术
1.创建方式
1、继承thread类
Thread t = new Thread(){ @Override public void run() { } }; t.start();
2、实现Runnable接口
Thread t1 = new Thread(new Runnable() { @Override public void run() { while (true) { } } }); t1.start();
3、实现Callable接口
ExecutorService pool = Executors.newCachedThreadPool(); Future future = pool.submit(new Callable() { public Object call() throws Exception { return null; } });
2.比较
1、Thread VS Runnable
- java不支持多继承,允许实现多个接口。Thread是类,Runnable是接口
- Runnable适合于资源的共享(多个Thread使用相同的Runnable)
- public class Thread extends Object implements Runnable. Thread是Runnable接口的子类
2、Runnable VS Callable
- Callable的 call() 方法可以返回Future类型结果和抛出异常,而Runnable的run()方法没有这些功能
- Callable通常利用ExecutorService的submit方法去启动call方法,Runnable还可以通过Thread的run方法启动run方法
二、传统定时器Timer
1、创建
到点执行,参数(TimerTask task, Date time),或者(TimerTask task, long delay)延迟多久后执行
new Timer().schedule(new TimerTask() { @Override public void run() { } }, new Date());
延迟多久执行,然后定时执行,参数(TimerTask task, long delay, long period)或者(TimerTask task, Date firstTime, long period)到点执行,然后定时执行
new Timer().schedule(new TimerTask() { @Override public void run() { }, 1000, 5000})
还有类似的scheduleAtFixedRate(TimerTask task, long delay, long period)
及scheduleAtFixedRate(TimerTask task, Date firstTime,long period)
2、schedule和scheduleAtFixedRate区别
- 2个参数的schedule:如果当前时间超过第一次执行时间,则立即执行,否则到定时时间执行
- 3个参数的schedule:如果当前时间超过第一次执行时间,则立即执行,否则到定时时间执行。下一个任务执行一定是在上一个任务执行完之后执行。下一次任务执行的时间需要看上一个任务执行多久exceTime及周期时间period,如果exceTime>period则立即执行,否则等待period时间再执行。
- scheduleAtFixedRate:每个任务执行的时间应该是定下了的。如果中间有作业处理时间太长导致后面的不能如期定时执行,则会立即执行后面的作业,直到追上了某一个任务的定时。如果当前时间超过第一次执行时间,则后面所有的作业都会立即执行,直到追上了某一个任务的定时。因为fixed-rate,可能导致同一时间重复执行,所以TimerTask中的执行体需要考虑同步(不是很懂)
schedule示例:
new Timer().schedule(new TimerTask(){ public void run() { try { System.out.println("execute task! "+ dateFormatter.format(this.scheduledExecutionTime())); Random random = new Random(); int slpTime = random.nextInt(3)*1000 + 4000; System.out.println("exec time:" + slpTime); Thread.sleep(slpTime); } catch (InterruptedException e) { e.printStackTrace(); } } },startDate, 5 * 1000);
输出结果:
execute task! 2017-12-14 23:26:22 // 当前时间超过了设定了首次执行时间,立即执行 exec time:1000 // 第一次执行时间为1s小于周期时间2s execute task! 2017-12-14 23:26:24 // 所以第二次在第一次执行时间2s之后执行 exec time:2000 // 第三次次执行时间为2s刚好等于周期时间2s execute task! 2017-12-14 23:26:26 // 所以第三次在第二次执行时间2s之后执行 exec time:3000 // 第三次执行时间为3s大于周期时间2s execute task! 2017-12-14 23:26:29 // 所以第四次在第三次执行时间3s之后执行 exec time:1000 // 之后就类似 execute task! 2017-12-14 23:26:31 exec time:2000 execute task! 2017-12-14 23:26:33 exec time:3000 execute task! 2017-12-14 23:26:36 exec time:1000 execute task! 2017-12-14 23:26:38
scheduleAtFixedRate示例:
System.out.println("start time: " + dateFormatter.format(new Date())); new Timer().scheduleAtFixedRate(new TimerTask(){ int i = 0; int slpTimes[] = new int[] {2000,4000,100,100,100}; public void run() { try { System.out.println("execute task:" + i + "! "+ dateFormatter.format(this.scheduledExecutionTime()) + " now time: " + dateFormatter.format(new Date())) ; int slpTime = slpTimes[i++%slpTimes.length]; System.out.println("exec time:" + slpTime); Thread.sleep(slpTime); } catch (InterruptedException e) { e.printStackTrace(); } } },startDate, 2 * 1000);
输出结果:
start time: 2017-12-15 00:00:09 //开始执行时间未到定时 execute task:0! 2017-12-15 00:01:00 now time: 2017-12-15 00:01:00 //定时开始执行 exec time:2000 //刚好执行2s execute task:1! 2017-12-15 00:01:02 now time: 2017-12-15 00:01:02 //所以第二次在规定时间执行 exec time:4000 //第二次执行2s,导致第三次延迟执行(第三次应该在2017-12-15 00:01:04执行) execute task:2! 2017-12-15 00:01:04 now time: 2017-12-15 00:01:06 //第三次在2017-12-15 00:01:06执行 exec time:100 //第三次执行100ms execute task:3! 2017-12-15 00:01:06 now time: 2017-12-15 00:01:06 //因为之前导致了延迟,需要追赶,所以立即执行,以下类似 exec time:100 execute task:4! 2017-12-15 00:01:08 now time: 2017-12-15 00:01:08 exec time:100 execute task:5! 2017-12-15 00:01:10 now time: 2017-12-15 00:01:10 exec time:2000 execute task:6! 2017-12-15 00:01:12 now time: 2017-12-15 00:01:12
3、Timer的缺陷
Timer的替代品ScheduledExecutorService,这个不在本文进行介绍,后面会进行阐述ScheduledExecutorService.
参考资料:
《多线程视频》张孝祥
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端