您的位置:首页 > 其它

TimerTask 出现IllegalStateException:Task already scheduled or cancelled.

2017-06-06 17:01 423 查看

抛出该错误的场景

需求:写一个定时器,定时打开和关闭继电器。可以随时暂停,更改关闭和打开时间

出现问题:
定时器的TimerTask只能被shceduler一次,所以当再次调用时,就会抛出该IllegalStateException:Task already scheduled or cancelled.


查找问题

debug查看代码后发现,task有个标识符state

/**
* The state of this task, chosen from the constants below.
*/
int state = VIRGIN;

/**
* This task has not yet been scheduled.
*/
static final int VIRGIN = 0;

/**
* This task is scheduled for execution.  If it is a non-repeating task,
* it has not yet been executed.
*/
static final int SCHEDULED   = 1;

/**
* This non-repeating task has already executed (or is currently
* executing) and has not been cancelled.
*/
static final int EXECUTED    = 2;

/**
* This task has been cancelled (with a call to TimerTask.cancel).
*/
static final int CANCELLED   = 3;


当实例被调度,之后状态就会改变,当状态不等于VIRGIN 时,就会抛出错误,看源码

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) {
if (task.state != TimerTask.VIRGIN)    //当state不等于0时,就会跑
throw new IllegalStateException(
"Task already scheduled or cancelled");
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.SCHEDULED;
}

queue.add(task);
if (queue.getMin() == task)
queue.notify();
}
}


解决问题

1、通过改变标识符state来达到目的,但state是默认的,访问权限只有包和同个类,所以我们通过反射来设置
timer = new Timer();
task = RelayOpenTask.getIntance();
//task.setMap(uuidMap, this);
Field field;
try {
field = TimerTask.class.getDeclaredField("state");
field.setAccessible(true);
field.set(task, 0);
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: