Java 时间,时间控制,线程超时小结。
——大牛说了做了什么要记下来,以便日后土鸡。
老师安排对webservice的时间进行监管,意思大概就是超时的webservice给kill掉。Webservice的开发基本和java
project的开发大致相同,可以在java project的基础上做修改搞定。所以先拿java project下手熟悉
java的时间,时间控制,线程超时。
先来看看 java的时间类。
import java.util.Date;
在这个类中主要的作用就是使用实时时间,我基本上把实时时间当做验证程序正确运行的一个验证结果。
System.out.println(new Date());
运行这条语句就可以输出当前时间。
有了这个当前时间我们就像进行时间的计算,
Date date1 = new Date();
try
{
Thread.sleep(2000);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
Date date2 = new Date();
long i = date1.getTime() - date2.getTime();
这样计算出来的i是以毫秒为单位的时间差。
进入第二步,我有一个想法比如说有一个函数,我能允许它运行的时间是一个确定值,当超出这个时间之后我想把它kill掉。这个如何实现。这两天走了不少弯路但也学到不少技术。
弯路:用while循环控制运行时间。经过验证发现这是不行的。比如如下代码
while((new
Date(System.currentTimeMillis())).getTime()-date2.getTime()<=3000)
{
lasting(4000);
}
其中lasting就是一个延迟函数,其实根据语法也可以看出来因为在进入while循环后就直接运行lasting函数直到lasting函数执行完了之后才去检查while的判断条件,当然是不能达到目的的。
所以说为了能够达到目的就需要有一个实时的时钟来检测时间,于是我想到用一个线程来监测实时时间。并且我把需要监测运行时间的方法也用一个线程来运行。这样就出现了一个问题,就是监视时间的线程我们不妨叫做timer,需要同限定运行时间的进程不妨设为lasting进行交互,这是因为至少要在lasting超时的时候把它kill掉。代码如下。
import
java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Calendar;
import java.util.Timer;
import java.io.IOException;
class lasting extends Thread
{
public int i=0;
public void run()
{
//long i=System.currentTimeMillis();
while(i<=300)
{
i++;
try
{
sleep(70);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("lasting finished");
}
}
class ThreadTimer extends Thread
{
private lasting t;
public int k=0;
public ThreadTimer(lasting tt)
{
t=tt;
}
public void run()
{
while(k<=200)
{
k++;
System.out.println(t.i);
try
{
sleep(30);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
t.stop();
}
}
public class timedo
{
public static void main(String[] args)
{
lasting lastt = new lasting();
Thread timet = new ThreadTimer(lastt);
lastt.start();
timet.start();
}
}
最后可以发现在控制台的输出根本达不到300,lasting就被kill掉了。因为需要在timer线程和lasting线程进行通信交互所以我在timer线程中定义了一个private
lasting t;用来引用lasting,然后调用stop()来停止。
这样虽然可以达到目的,但是个人总是感觉怪怪的特别是用一个线程来控制一个线程,而且java对实时的支持也不是很好。
更进一步来实现对方法或者线程的实时控制。现在我不想再定义一个lasting的引用来完成这项任务,我想在时间到了的时候根据线程的特征找到lasting线程然后把它kill掉。这样就出现了一个问题如何找到特定的线程。
这里我想用线程的名字来判断特定的线程。
import
java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Calendar;
class simpleThread extends Thread
{
public boolean flag = false;
public Object simpleThread ()
{
try
{
return this.clone();
}
catch (CloneNotSupportedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public void run()
{
try
{
Thread.sleep(300);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
flag = true;
System.out.println("simpleThread finished");
}
}
public class timercancel
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
simpleThread sthread = new simpleThread();
sthread.setName("zhu");//给线程设置特征,在这里我选择使用一个特定的线程名字。
sthread.start();
int n = Thread.activeCount();
System.out.println(n);
Thread[] threads = new Thread[n];
Thread.enumerate(threads);
for(int i =0 ;i
{
Thread thread = threads[i];
System.out.println(thread.getName());
}
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
if(!sthread.flag)
{
sthread.stop();
System.out.println("kill
thread");//如果线程没有自动完成运行就是被kill掉了。
}
}
}
其实这个例子没有从本质上解决不定义引用的问题,因为我是在main函数中定义了simpleThread这个需要被监测的线程,当然可以再main中操作它。所以我还是不太满意。继续研究发现了timer这个java库。
对于timer的功能性介绍网上有很多文章大家可以参考,我这里不再叙述。我做了一个实验代码如下:
import java.util.Timer;
import java.util.Date;
public class MyTimer
{
public static void main(String[] args)
{
Timer timer = new Timer();
// 在1秒后执行此任务,每次间隔2秒,如果传递一个Data参数,就可以在某个固定的时间执行这个任务.
MyTask mytask = new MyTask();
timer.schedule(mytask, 1000,2000);
System.out.println(new Date());
// 这个是用来停止此任务的,否则就一直循环执行此任务了
try
{
Thread.sleep(10000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
// 使用这个方法退出任务
mytask.cancel();// 同样cancel不了 正在执行的thread。
timer.cancel();//正在执行的会执行完,cancel后面的。
System.out.println(new Date());
}
static class MyTask extends
java.util.TimerTask
{
@Override
public void run()
{
System.out.println("started!"+(new Date()));
try
{
Thread.sleep(10000);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Done !"+(new Date()));
}
}
}
这个实验意思是我的timerTask任务的运行时间是10000毫秒,然后我用timer调度它,这个调度是这样的先延迟一秒钟然后在开始运行,然后每隔2秒又开始一个新的timerTask,然后我在main中等待10000毫秒,然后
mytask.cancel();// 同样cancel不了 正在执行的thread。
timer.cancel();//正在执行的会执行完,cancel后面的。
发现正在执行的thread,不能被cancel掉,它们还是会最后运行完,并且输出结果,但后续的thread被cancel掉了。还有如果当我把task当中的sleep里面的参数改成3000会发现如下输出结果。
Tue Aug 14 16:28:50 CST 2012
started!Tue Aug 14 16:28:51 CST 2012
Done !Tue Aug 14 16:28:54 CST 2012
started!Tue Aug 14 16:28:54 CST 2012
Done !Tue Aug 14 16:28:57 CST 2012
started!Tue Aug 14 16:28:57 CST 2012
Done !Tue Aug 14 16:29:00 CST 2012
started!Tue Aug 14 16:29:00 CST 2012
Tue Aug 14 16:29:00 CST 2012
Done !Tue Aug 14 16:29:03 CST 2012
由此可以发现这个timerTask不是每隔两秒就开始一个新的timerTask
的。而是3秒,timer的调度会等一个task完成后才调用一个新的task。
综上,这样尝试不能解决我的问题,就是在规定时间到了的时候cancel掉task。
现在怎么办?网上查资料后发现了一种叫做守护线程的技术,个人感觉它的技术和我做timer线程和lasting线程的思想非常接近。所谓守护线程就也是把需要运行的方法交给一个线程来运行,然后在这个线程中设置一个定时器timer,timer的作用是在规定的运行时间后开始运行timerTask任务。比如说我想让方法myTest()运行两秒,我就设置一个timer(timerTask,2000),这样tiemr会在2秒后运行timerTask,而timerTask所运行的语句就是kill掉myTest()方法的。用timer来kill线程的思路就是这样。
代码如下:
import java.util.Timer;
import java.util.TimerTask;
import java.util.Date;
public class MyTimer2
{
private String name;
private long timeOut;
private Thread thread;
public MyTimer2(String name, long timeOut)
{
this.name = name;
this.timeOut = timeOut;
}
public void startShutdownTimeout(long
timeOut)
{
new Timer(true).schedule(new TimerTask()
{ // true,表示执行的线程是一个守护线程
@Override
public void run()
{
System.out.println("线程" + name + "超时,执行守护线程 !");
// System.exit(1);
thread.stop();
}
}, timeOut);//timer 在timeout后 调用。不重复执行。
}
public void myTest()
{
thread = new Thread()
{
@Override
public void run()
{
startShutdownTimeout(timeOut); // 该线程受到守护线程的作用
System.out.println(name + "Begin");
try
{
Thread.sleep(200); // 函数要执行至少200毫秒
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(name + "Over");
}
};
thread.start();
}
public static void main(String[] args)
{
MyTimer2 m1 = new MyTimer2("1 - ", 100);
MyTimer2 m2 = new MyTimer2("2 - ", 180);
MyTimer2 m3 = new MyTimer2("3 - ", 250);
MyTimer2 m4 = new MyTimer2("4 - ", 320);
m1.myTest();
m2.myTest();
m3.myTest();
m4.myTest();
}
}
运行结果如下:
1 - Begin
3 - Begin
4 - Begin
2 - Begin
线程1 - 超时,执行守护线程 !
线程2 - 超时,执行守护线程 !
4 - Over
3 - Over
感谢网上无偿提供代码的人们,你们才是真正的英雄。好人一生平安。