java timertask 安全_记一次线程Timer导致的线程安全问题修正

接收别人的项目别人的项目,发现了一段很夸张的代码,居然用源码的方式实现websocket……

还单独开了一个端口,多线程websocket,在调用Service的服务,定时执行什么的。

绕了好半天没有缓过劲来,不过自己debug的时候,没发现什么问题,就想着随它去吧。

结果过几天,报出了以下问题。

java.util.ConcurrentModificationException

at java.util.HashMap$HashIterator.nextNode(HashMap.java:1437)

at java.util.HashMap$EntryIterator.next(HashMap.java:1471)

at java.util.HashMap$EntryIterator.next(HashMap.java:1469)

.....

好吧,这是多线程访问HashMap导致的线程不安全问题。想改,但是单纯看实在看不出来。于是把原本代码,简化简化,做了个debug用项目出来。

package error_test_001;

import java.util.*;

public class error_test {

public static void main(String[] arge) throws InterruptedException {

Test ttmtransService = new Test();

Runnable runnable = new Runnable() {

@Override

public void run() {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

ttmtransService.StartTask();

}

};

Thread thread[] = new Thread[100];

for (int i = 0; i < thread.length; i++) {

thread[i] = new Thread(runnable);

thread[i].start();

}

}

}

class Test{

/**返回结果数据**/

private Map ResultData=new HashMap();

/**定时器**/

public static Timer TaskTimer;

/**查询任务**/

private TaskQuery mytask;

/**开始执行任务**/

public synchronized void StartTask(){

if(TaskTimer != null){

CloseTimer();

}

TaskTimer=new Timer();

mytask=new TaskQuery();

TaskTimer.schedule(mytask, new Date(),1000);

}

/**

* 关闭定时器

*/

private synchronized void CloseTimer(){

TaskTimer.cancel();

TaskTimer.purge();

TaskTimer = null;

}

public class TaskQuery extends TimerTask{

/** 原来时间戳 **/

private long time;

/** 现在时间戳 **/

private long now;

/** 执行中flg **/

private boolean flgRunning = false;

public void run(){

if (flgRunning){

return;

}

flgRunning = true;

try {

System.out.print("开始执行...");

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("结束执行...");

}finally {

// 结束时,flag

flgRunning = false;

}

}

}

}

上边的项目执行:

开始执行...开始执行...开始执行...结束执行...

结束执行...

结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

好吧,至少确定有线程问题了。

其实,代码已经简化很多了,正常的一个Timer的话,是【task执行->task执行完毕->定时等待->task执行->task执行完毕->定时等待】,这样依次执行的,至少个人debug,在类似单线程环境下基本没为什么问题。

于是再仔细考虑了下代码,果然,问题出在Timer和TaskQuery的创建上呢,每次new对象,于是和之前的没关系,相互之间各自执行了。于是把定时器的开始和关闭方法StartTask和CloseTimer中的内容,改为全新建,全加的方法

package error_test_001;

import java.util.*;

public class error_test {

public static void main(String[] arge) throws InterruptedException {

Test ttmtransService = new Test();

Runnable runnable = new Runnable() {

@Override

public void run() {

try {

Thread.sleep(1000);

ttmtransService.StartTask();

Thread.sleep(5000);

ttmtransService.CloseTimer();

ttmtransService.StartTask();

Thread.sleep(5000);

ttmtransService.CloseTimer();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

};

Thread thread[] = new Thread[100];

for (int i = 0; i < thread.length; i++) {

thread[i] = new Thread(runnable);

thread[i].start();

}

}

}

class Test{

/**返回结果数据**/

private Map ResultData=new HashMap();

/**定时器**/

public static Timer TaskTimer;

/**查询任务**/

private TaskQuery mytask;

/**开始执行任务**/

public synchronized void StartTask(){

if(TaskTimer == null){

System.out.print("StartTask...");

TaskTimer=new Timer();

mytask=new TaskQuery();

TaskTimer.schedule(mytask, new Date(),1000);

}

}

/**

* 关闭定时器

*/

public synchronized void CloseTimer(){

if(TaskTimer != null){

System.out.print("CloseTimer...");

TaskTimer.cancel();

TaskTimer.purge();

TaskTimer = null;

}

}

public class TaskQuery extends TimerTask{

/** 原来时间戳 **/

private long time;

/** 现在时间戳 **/

private long now;

/** 执行中flg **/

private boolean flgRunning = false;

public void run(){

if (flgRunning){

return;

}

flgRunning = true;

try {

System.out.print("开始执行...");

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("结束执行...");

}finally {

// 结束时,flag

flgRunning = false;

}

}

}

}

然后看看结果:

StartTask...开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...开始执行...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...开始执行...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...开始执行...结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...CloseTimer...结束执行...

嗯……开始是没错,但是中间尝试多线程停止timer并重新开始的时候出问题了。反复的开始关闭交错执行,每次都会新开区一个TaskQuery,导致有很多tark新执行。而这些TaskQuery都是new出来的,于是使用synchronized也无效。

Timer的TaskQuery虽然取消,但是TaskQuery也不能执行到一半强制中断。所以继续执行时1. 正常的。

然后,new出来的TaskQuery,在一次使用后,不能再次放入Timer中,所以new是正常的。

然后Timer没发判断内部的执行状态,没想做延时也不行。

好吧,然后又是看代码……说起来,里边有个flgRunning呢,定义在内部是没什么用的,那么拿出来试试?

package error_test_001;

import java.util.*;

public class error_test {

public static void main(String[] arge) throws InterruptedException {

Test ttmtransService = new Test();

Runnable runnable = new Runnable() {

@Override

public void run() {

try {

Thread.sleep(1000);

ttmtransService.StartTask();

Thread.sleep(5000);

ttmtransService.CloseTimer();

ttmtransService.StartTask();

Thread.sleep(10000);

ttmtransService.CloseTimer();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

};

Thread thread[] = new Thread[100];

for (int i = 0; i < thread.length; i++) {

thread[i] = new Thread(runnable);

thread[i].start();

}

}

}

class Test{

/**返回结果数据**/

private Map ResultData=new HashMap();

/**定时器**/

public static Timer TaskTimer;

/**查询任务**/

private TaskQuery mytask;

/** 执行中flg **/

private boolean flgRunning = false;

/**开始执行任务**/

public synchronized void StartTask(){

if(TaskTimer == null){

System.out.print("StartTask...");

TaskTimer=new Timer();

mytask=new TaskQuery();

TaskTimer.schedule(mytask, new Date(),1000);

}

}

/**

* 关闭定时器

*/

public synchronized void CloseTimer(){

if(TaskTimer != null){

System.out.print("CloseTimer...");

TaskTimer.cancel();

TaskTimer.purge();

TaskTimer = null;

}

}

public class TaskQuery extends TimerTask{

/** 原来时间戳 **/

private long time;

/** 现在时间戳 **/

private long now;

public void run(){

if (flgRunning){

return;

}

flgRunning = true;

try {

System.out.print("开始执行...");

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("结束执行...");

}finally {

// 结束时,flag

flgRunning = false;

}

}

}

}

结果:

StartTask...开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...结束执行...

CloseTimer...StartTask...CloseTimer...StartTask...开始执行...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...CloseTimer...StartTask...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...结束执行...

开始执行...CloseTimer...结束执行...

好吧,可以接受。这算是手动的加了个锁。能解决问题就好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值