H5网站整站,宝安中心区范围,网页设计前端要学什么,佳木斯市城乡建设局网站java项目中如何利用多线程实现一个定时器任务发布时间#xff1a;2020-11-10 16:04:03来源#xff1a;亿速云阅读#xff1a;86作者#xff1a;Leah今天就跟大家聊聊有关java项目中如何利用多线程实现一个定时器任务#xff0c;可能很多人都不太了解#xff0c;为了让大家…java项目中如何利用多线程实现一个定时器任务发布时间2020-11-10 16:04:03来源亿速云阅读86作者Leah今天就跟大家聊聊有关java项目中如何利用多线程实现一个定时器任务可能很多人都不太了解为了让大家更加了解小编给大家总结了以下内容希望大家根据这篇文章可以有所收获。在Java中Timer是java.util包中的一个工具类提供了定时器的功能。我们可以创建一个Timer对象然后调用其schedule方法在某个特定的时间去执行一个特定的任务。并且你可以让其以特定频率一直执行某个任务这个任务是用TimerTask来描述的我们只需要将要进行的操作写在TimerTask类的run方法中即可。先附上两个小例子一遍让读者了解什么是定时器。接着再分析其中的一些源码实现。第一个小例子package com.zkn.newlearn.thread;import java.util.Timer;import java.util.TimerTask;/*** 传统的定时器* Created by zkn on 2016/11/1.*/public class TraditionalTimerTest01 {public static void main(String[] args){//TimerTask是Runnable接口的一个实现类是它是一个抽像类//schedule是一个重载方法第一个参数TimerTask的实现类。// 第二个参数是第一次执行的时间。// 第三个参数是间隔时间new Timer().schedule(new TimerTask() {Overridepublic void run() {System.out.println(这是一个定时器任务!);}},1000,2000);}}第二个小例子让任务1每隔4秒执行让任务2每隔2秒执行。依次反复。package com.zkn.newlearn.thread;import java.util.Timer;import java.util.TimerTask;/*** Created by zkn on 2016/11/1.*/public class TraditionalTimerTest02 {public static void main(String[] args){new Timer().schedule(new MyTimerTask01(),4000);}private static class MyTimerTask01 extends TimerTask{Overridepublic void run() {System.out.println(我是TimerTask1我被执行了!);new Timer().schedule(new MyTimerTask02(),2000);}}private static class MyTimerTask02 extends TimerTask {Overridepublic void run() {System.out.println(我是TimerTask2我被执行了!);new Timer().schedule(new MyTimerTask01(),4000);}}}大家一定会很好奇定时器是怎么执行的接下来我们来看一下Timer中的主要代码。private final TaskQueue queue new TaskQueue();/*** The timer thread.*/private final TimerThread thread new TimerThread(queue);注意着两段代码是很重要的两段代码。TaskQueue和TimerThread都是Timer的内部类。TaskQueue是一个执行任务的优先队列。TimerThread是一个继承了Thread的线程类。他们两个在定时器中起着至关重要的作用定时器基本上就是靠这两个类支撑的。 接下来我们来一下Timer的构造方法public Timer(String name) {thread.setName(name);thread.start();}public Timer() {this(Timer- serialNumber());}无参的这个构造函数会调用这个有参的构造函数在这个有参的构造函数中你看到了什么thread.start()看着是不是很眼熟啊没错在new Timer()的时候就是启动了一个线程。而启动这个线程的对象就是上面的TimerThread接下来我们来看一下TimerThread的run方法中干了些什么public void run() {try {mainLoop();} finally {// Someone killed this Thread, behave as if Timer cancelledsynchronized(queue) {newTasksMayBeScheduled false;queue.clear(); // Eliminate obsolete references}}}这个run方法中主要是干了两件事一调用mainLoop()这个死循环的方法我们在下面会详细分析二finally代码块终止定时任务。终止定时任务的这个没什么说的我们主要来看一下mainLoop()这个方法。private void mainLoop() {while (true) { // 开始死循环try {TimerTask task;boolean taskFired;synchronized(queue) {// 如果任务队列中为空并且定时任务没有被取消话线程被挂起 等待执行任务的到来while (queue.isEmpty() newTasksMayBeScheduled)queue.wait();if (queue.isEmpty())break; // 如果任务队列中没有任务了则结束循环结束任务// 如果队列中有执行任务的话接着往下走long currentTime, executionTime;task queue.getMin();synchronized(task.lock) {if (task.state TimerTask.CANCELLED) {queue.removeMin();continue; // 如果执行任务被取消的话 则移除当前任务。这里会重新排队列里的任务执行顺序}currentTime System.currentTimeMillis();executionTime task.nextExecutionTime;if (taskFired (executionTimecurrentTime)) {if (task.period 0) { // 如果只执行一次的话则在执行完之后结束执行任务queue.removeMin();task.state TimerTask.EXECUTED;} else { // 如果是固定频率执行任务的话则计算下次执行的时间queue.rescheduleMin(task.period0 ? currentTime - task.period: executionTime task.period);}}}if (!taskFired) // 不到任务执行的时候 等待线程调用queue.wait(executionTime - currentTime);}if (taskFired) // 任务执行时间到调用任务的run方法执行任务task.run();} catch(InterruptedException e) {}}}这个类比较长具体的执行操作我在注释里都标注了。这个类基本上干了这样几件事循环调用任务队列中的任务执行队列中的任务。执行任务是什么时候放到执行队列中的呢?在schedule方法。我们来看看schedule的实现public void schedule(TimerTask task, long delay, long period) {if (delay 0) // 如果第一次执行的时间小于0 抛出异常throw new IllegalArgumentException(Negative delay.);if (period 0) //间隔时间小于等于 0 抛出异常throw new IllegalArgumentException(Non-positive period.);sched(task, System.currentTimeMillis()delay, -period);}private void sched(TimerTask task, long time, long period) {if (time 0)throw new IllegalArgumentException(Illegal execution time.);// Constrain value of period sufficiently to prevent numeric// overflow while still being effectively infinitely large.这个间隔时间到死基本上也执行不到if (Math.abs(period) (Long.MAX_VALUE 1))period 1;synchronized(queue) {if (!thread.newTasksMayBeScheduled) //在任务的执行方法中 如果定时任务已经被取消的话 则抛出异常throw new IllegalStateException(Timer already cancelled.);synchronized(task.lock) { //object对象锁if (task.state ! TimerTask.VIRGIN) // 刚开是执行任务的时候 任务的状态应该是0的throw new IllegalStateException(Task already scheduled or cancelled);task.nextExecutionTime time; //下次执行时间 在上面的mainLoop方法中有用到task.period period; //设置任务的间隔时间在上面的mainLoop方法中有用到task.state TimerTask.SCHEDULED; // 调度方法被调用 设置定时任务的状态为 已调度未执行}queue.add(task); //把执行任务加入到任务队列中if (queue.getMin() task)queue.notify(); // 如果任务队列中的第一个任务为当前任务的话则把当前任务放入到等锁池中 等待执行}}shedule这个方法做的事情比较简单。最主要的作用是把TimerTask放到任务队列中。下面我们大致看一下TaskQueue的代码class TaskQueue {//定义一个TimerTask的堆数组 private TimerTask[] queue new TimerTask[128];//任务队列中的任务数 private int size 0;int size() {return size;}//添加任务到优先队列中 如果数组的长度不够的话会扩展数组void add(TimerTask task) {// Grow backing store if necessaryif (size 1 queue.length)queue Arrays.copyOf(queue, 2*queue.length);queue[size] task;fixUp(size);}//获取优先执行的任务TimerTask getMin() {return queue[1];}TimerTask get(int i) {return queue[i];}//移除掉排在第一位的不能执行的任务void removeMin() {queue[1] queue[size];queue[size--] null; // Drop extra reference to prevent memory leak 把对象置空 等待gc回收fixDown(1);}//删除任务队列队列中的任务 这里用来一个断言 来判断 i 不能大于 sizevoid quickRemove(int i) {assert i size;queue[i] queue[size];queue[size--] null; // Drop extra ref to prevent memory leak}//重新设置优先执行任务的执行时间 并对任务队列进行重新排序 以确保最优先的任务 优先被执行void rescheduleMin(long newTime) {queue[1].nextExecutionTime newTime;fixDown(1);}boolean isEmpty() {return size0;}//清空任务队列 定时任务结束void clear() {// Null out task references to prevent memory leakfor (int i1; isize; i)queue[i] null;size 0;}//两个堆排序 选出最优先的执行任务private void fixUp(int k) {while (k 1) {int j k 1;if (queue[j].nextExecutionTime queue[k].nextExecutionTime)break;TimerTask tmp queue[j]; queue[j] queue[k]; queue[k] tmp;k j;}}private void fixDown(int k) {int j;while ((j k 1) size j 0) {if (j size queue[j].nextExecutionTime queue[j1].nextExecutionTime)j; // j indexes smallest kidif (queue[k].nextExecutionTime queue[j].nextExecutionTime)break;TimerTask tmp queue[j]; queue[j] queue[k]; queue[k] tmp;k j;}}void heapify() {for (int i size/2; i 1; i--)fixDown(i);}}看完上述内容你们对java项目中如何利用多线程实现一个定时器任务有进一步的了解吗如果还想了解更多知识或者相关内容请关注亿速云行业资讯频道感谢大家的支持。