线程状态转换
图1 线程的状态
1)New :创建好线程对象,但没有启动的时候。
一个线程调用start()之后不一定会马上启动,此时进入就绪状态,等待得到资源。
2)就绪线程序通过Scheduler(调度程序)去确定是否运行。
3)Runing---dead:运行结束(非双向,为单向箭头)。
4)Runing---就绪:暂停(除了没有CPU,具备运行的所有条件)。
5)Runing-otherwise(阻塞):因程序原因:调用sleep或join之后,线程被阻塞。这时不具备运行的条件,此时线程进入阻塞池。sleep或join条件解除之后直接进入Runnable不进入running。
6)Lock pool:锁池状态。每个对象都有自己的锁池,锁池里放置了想获得对象锁的线程。
7)等待状态(wait pool):比如一个线程调用了某个对象的wait()方法,就进入了该对象的wait pool, 正在等待其它线程调用这个对象的notify()或者notifyAll()(这两个方法同样是继承自Object类)方法来唤醒它。
任务定时调度
通过Timer和Timetask,我们可以实现定时启动某个线程。
1)java.util.Timer
在这种实现方式中,Timer类作用是类似闹钟的功能,也就是定时或者每隔一定时间触发一次线程。其实,Timer类本身实现的就是一个线程,只是这个线程是用来实现调用其它线程的。
2)java.util.TimerTask任务类
TimerTask类是一个抽象类,该类实现了Runnable接口,所以该类具备多线程的能力。
在这种实现方式中,通过继承TimerTask使该类获得多线程的能力,将需要多线程执行的代码书写在run方法内部,然后通过Timer类启动线程的执行。
【示例1】java.util.Timer的使用
public class TestTimer {
public static void main(String[] args) {
Timer t1 = new Timer();
MyTask task1 = new MyTask();
// t1.schedule(task1,3000); //3秒后执行
t1.schedule(task1,5000,1000); //5秒以后每隔1秒执行一次!
// GregorianCalendar calendar1 = new GregorianCalendar(2010,0,5,14,36,57); //注意月份是0-11
// t1.schedule(task1,calendar1.getTime()); //指定时间定时执行
}
}
class MyTask extends TimerTask {
public void run() {
for(int i=0;i<100;i++){
System.out.println("任务1:"+i);
}
}
}
在实际使用时,一个Timer可以启动任意多个TimerTask实现的线程,但是多个线程之间会存在阻塞。所以如果多个线程之间如果需要完全独立运行的话,最好还是一个Timer启动一个TimerTask实现。
老鸟建议
实际开发中,我们可以使用开源框架quanz,更加方便的实现任务定时调度。实际上,quanz底层原理就是我们这里介绍的内容。
「全栈Java笔记」是一部能帮大家从零到一成长为全栈Java工程师系列笔记。笔者江湖人称 Mr. G,10年Java研发经验,曾在神州数码、航天院某所研发中心从事软件设计及研发工作,从小白逐渐做到工程师、高级工程师、架构师。精通Java平台软件开发,精通JAVAEE,熟悉各种流行开发框架。
笔记包含从浅入深的六大部分:
A-Java入门阶段
B-数据库从入门到精通
C-手刃移动前端和Web前端
D-J2EE从了解到实战
E-Java高级框架精解
F-Linux和Hadoop