2020/08/10更新:
增加 now() 方法,用于立刻执行任务;
增加 isStart() 方法,用于判断任务是否已经启动;
修改为实现 Runnable接口,方便使用线程池,同时保留start()方法;
最近有个需求是这样的:
实现一个HDFS的Bucket.在总大小超过128M或10分钟内没有新文件时,进行上传操作.
所以需要实现一个可以修改定时时间的定时任务.
代码如下
package com.run;
/**
* 可更新定时的定时任务线程
*
* @author MrBlack
* @date 2020/5/23 023 下午 6:19
*/
public class DelayThread implements Runnable {
private final Object lock = new Object();
/**
* 标识定时是否更新,
* 用于{@link #update(long)}通知{@link #loop()}
*/
private boolean update;
/**
* 标识任务是否已经启动
*/
private boolean start;
/**
* 具体的执行时间
*/
private long executionTime;
/**
* @param delay 定时时间,单位毫秒
*/
public DelayThread(long delay) {
executionTime = System.currentTimeMillis() + delay;
}
/**
* 更新定时时间
*
* @param delay 定时时间,单位毫秒
*/
public void update(long delay) {
if (start) return;
synchronized (lock) {
update = true;
executionTime = System.currentTimeMillis() + delay;
lock.notify();
}
}
/**
* 倒计时是否结束?
*
* @return true-任务已经启动, false-仍在倒计时
*/
public boolean isStart(){
return start;
}
/**
* 立刻执行任务
*/
public boolean now(){
synchronized (lock) {
this.start = true;
lock.notify();
}
}
private void loop() {
boolean flag = false;
while (true) {
synchronized (lock) {
// 既收到通知,也达到执行时间,退出循环
if (flag && !update) break;
long now = System.currentTimeMillis();
if (now < executionTime) {
try {
// 未达到执行时间,释放锁,wait到可执行时间
lock.wait(executionTime - now);
} catch (InterruptedException ignored) {
}
}
// 说明wait是被update方法唤醒的,更改update变量,表示我收到通知了,需要continue重新检查执行时间
if (update) {
update = false;
continue;
}
// 说明是收到通知后的第二次检查,满足执行条件
flag = true;
}
}
}
@Override
public void run() {
super.run();
loop();
}
public void start() {
new Thread(this).start();
}
}
需要设置定时的任务直接继承此类,继承构造方法,重写run方法即可.
通过构造方法指定定时时间,调用update(long)方法即可更新.