线程的生命周期
线程的生命周期一共有5个状态:new、runnable、running、blocked、dead。
- 线程生命周期的5种状态
- 线程常用方法
1.线程的生命周期
(1)新建(new Thread):当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动),也就说处于新生状态的线程有自己的内存空间,但该线程并没有运行。此时线程还不是活着的(not alive)。例如:
Thread thread = new Thread();
(2)就绪(runnable):线程已经被启动,正在等待被分配给CPU时间片。也就通过调用线程实例的start()方法来启动线程使线程进入就绪状态(runnable)。处于就绪状态的线程已经具备了运行条件,但还没有被分配到CPU,不一定会被立即执行,此时处于线程就绪队列,等待系统为其分配CPU,等待状态并不是执行状态。此时线程是活着的(alive)。
(3)运行(running):线程获得CPU资源正在执行任务(run()方法),此时除非线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运动到结束。此时线程是活着的(alive)。
(4)堵塞(blocked):由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,进入堵塞状态。
- 正在睡眠:用sleep(long t)方法可以使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。
- 正在等待:调用wait()方法。可调用notify()方法回到就绪状态。
- 被另一个线程所阻塞: 调用suspend()方法。可调用resume()方法恢复。
(5)死亡(dead):当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。
- 自然终止:正常运行run()方法后终止。
- 异常终止:调用stop()方法让一个线程终止运行。
处于Dead状态的线程不是活着的。
2,线程常用方法
与线程状态对应的常用方法有:
- void run():创建该类的子类时必须实现的方法。
- void start():开启线程的方法。
- static void sleep(long t)/static void sleep(long millis,int nanos):释放CPU执行权,不释放锁。当前线程睡眠/millis的时间(millis指定睡眠时间是其最小的不执行时间,因为sleep(millis)休眠到达后,无法保证会被JVM立即调度),sleep()是一个静态方法(static method),所以它不会停止其它的线程也处于休眠状态。线程sleep()时不会失去拥有的对象锁。作用是:保持对象锁,让出CPU,调用目的是不让当前线程独自霸占该进程所获取的CPU资源,以留一定的时间给其它线程执行的机会。
- final void wait():释放CPU的执行权,释放锁。当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池(Waiting Pool)中,同时失去了对象的机锁-暂时的,wait()后还要返还对象锁。当前线程必须拥有当前对象的锁,如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常,所以wait()必须在synchronized block中调用。
- final void notify()/notifyAll():唤醒在当前对象等待池中等待的第一个线程/所有线程。notify()/notifyAll()也必须拥有相同的对象锁,否则也会抛出IllegalMonitorStateException异常。
- static void yied():可以对当前线程进行临时暂停,让出CPU的使用权,给其它线程执行机会、让同等优先权的线程运行(但并不保证当前线程会被JVM再次调度、使该线程重新进入Running状态),如果没有等同优先权的线程,那么yield()方法将不起作用。
用一张图片表示: