java线程之线程的生命周期的使用

与人有生老病死一样,线程也同样要经历开始(等待)、运行、挂起和停止四种不同的状态。这四种状态都可以通过Thread类中的方法进行控制。下面给出了Thread类中和这四种状态相关的方法。


代码如下:

// 开始线程
     public void start( );
     public void run( );

// 挂起和唤醒线程
     public void resume( );     // 不建议使用
     public void suspend( );    // 不建议使用
     public static void sleep(long millis);
     public static void sleep(long millis, int nanos);

// 终止线程
     public void stop( );       // 不建议使用
     public void interrupt( );

// 得到线程状态
     public boolean isAlive( );
     public boolean isInterrupted( );
     public static boolean interrupted( );

// join方法
     public void join( ) throws InterruptedException;

一、创建并运行线程

线程在建立后并不马上执行run方法中的代码,而是处于等待状态。线程处于等待状态时,可以通过Thread类的方法来设置线程不各种属性,如线程的优先级(setPriority)、线程名(setName)和线程的类型(setDaemon)等。

当调用start方法后,线程开始执行run方法中的代码。线程进入运行状态。可以通过Thread类的isAlive方法来判断线程是否处于运行状态。当线程处于运行状态时,isAlive返回true,当isAlive返回false时,可能线程处于等待状态,也可能处于停止状态。下面的代码演示了线程的创建、运行和停止三个状态之间的切换,并输出了相应的isAlive返回值。


代码如下:

package chapter2;

public class LifeCycle extends Thread
 {
     public void run()
     {
         int n = 0;
         while ((++n) < 1000);       
     }

public static void main(String[] args) throws Exception
     {
         LifeCycle thread1 = new LifeCycle();
         System.out.println("isAlive: " + thread1.isAlive());
         thread1.start();
         System.out.println("isAlive: " + thread1.isAlive());
         thread1.join();  // 等线程thread1结束后再继续执行
         System.out.println("thread1已经结束!");
         System.out.println("isAlive: " + thread1.isAlive());
     }
 }

要注意一下,在上面的代码中使用了join方法,这个方法的主要功能是保证线程的run方法完成后程序才继续运行,这个方法将在后面的文章中介绍

上面代码的运行结果:


代码如下:

isAlive: false
isAlive: true
thread1已经结束!
isAlive: false

二、挂起和唤醒线程

一但线程开始执行run方法,就会一直到这个run方法执行完成这个线程才退出。但在线程执行的过程中,可以通过两个方法使线程暂时停止执行。这两个方法是suspend和sleep.在使用suspend挂起线程后,可以通过resume方法唤醒线程。而使用sleep使线程休眠后,只能在设定的时间后使线程处于就绪状态(在线程休眠结束后,线程不一定会马上执行,只是进入了就绪状态,等待着系统进行调度)。

虽然suspend和resume可以很方便地使线程挂起和唤醒,但由于使用这两个方法可能会造成一些不可预料的事情发生,因此,这两个方法被标识为deprecated(抗议)标记,这表明在以后的jdk版本中这两个方法可能被删除,所以尽量不要使用这两个方法来操作线程。下面的代码演示了sleep、suspend和resume三个方法的使用。


代码如下:

package chapter2;

public class MyThread extends Thread
 {
     class SleepThread extends Thread
     {
         public void run()
         {
             try
             {
                 sleep(2000);
             }
             catch (Exception e)
             {
             }
         }
     }
     public void run()
     {
         while (true)
             System.out.println(new java.util.Date().getTime());
     }
     public static void main(String[] args) throws Exception
     {
         MyThread thread = new MyThread();
         SleepThread sleepThread = thread.new SleepThread();
         sleepThread.start(); // 开始运行线程sleepThread
         sleepThread.join();  // 使线程sleepThread延迟2秒
         thread.start();
         boolean flag = false;
         while (true)
         {
             sleep(5000);  // 使主线程延迟5秒
             flag = !flag;
             if (flag)
                 thread.suspend();
             else
                 thread.resume();
         }
     }
 }

从表面上看,使用sleep和suspend所产生的效果类似,但sleep方法并不等同于suspend.它们之间最大的一个区别是可以在一个线程中通过suspend方法来挂起另外一个线程,如上面代码中在主线程中挂起了thread线程。而sleep只对当前正在执行的线程起作用。在上面代码中分别使sleepThread和主线程休眠了2秒和5秒。在使用sleep时要注意,不能在一个线程中来休眠另一个线程。如main方法中使用thread.sleep(2000)方法是无法使thread线程休眠2秒的,而只能使主线程休眠2秒。

在使用sleep方法时有两点需要注意:

1. sleep方法有两个重载形式,其中一个重载形式不仅可以设毫秒,而且还可以设纳秒(1,000,000纳秒等于1毫秒)。但大多数操作系统平台上的Java虚拟机都无法精确到纳秒,因此,如果对sleep设置了纳秒,Java虚拟机将取最接近这个值的毫秒。

2. 在使用sleep方法时必须使用throws或try{……}catch{……}.因为run方法无法使用throws,所以只能使用try{……}catch{……}.当在线程休眠的过程中,使用interrupt方法(这个方法将在2.3.3中讨论)中断线程时sleep会抛出一个InterruptedException异常。sleep方法的定义如下:


代码如下:

1 public static void sleep(long millis)  throws InterruptedException
2 public static void sleep(long millis,  int nanos)  throws InterruptedException

三、终止线程的三种方法

有三种方法可以使终止线程。

1.  使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。

2.  使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。

3.  使用interrupt方法中断线程。

1. 使用退出标志终止线程

当run方法执行完后,线程就会退出。但有时run方法是永远不会结束的。如在服务端程序中使用线程进行监听客户端请求,或是其他的需要循环处理的任务。在这种情况下,一般是将这些任务放在一个循环中,如while循环。如果想让循环永远运行下去,可以使用while(true){……}来处理。但要想使while循环在某一特定条件下退出,最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出。下面给出了一个利用退出标志终止线程的例子。


代码如下:

package chapter2;

public class ThreadFlag extends Thread
 {
     public volatile boolean exit = false;

public void run()
     {
         while (!exit);
     }
     public static void main(String[] args) throws Exception
     {
         ThreadFlag thread = new ThreadFlag();
         thread.start();
         sleep(5000); // 主线程延迟5秒
         thread.exit = true;  // 终止线程thread
         thread.join();
         System.out.println("线程退出!");
     }
 }

在上面代码中定义了一个退出标志exit,当exit为true时,while循环退出,exit的默认值为false.在定义exit时,使用了一个Java关键字volatile,这个关键字的目的是使exit同步,也就是说在同一时刻只能由一个线程来修改exit的值,

2. 使用stop方法终止线程

使用stop方法可以强行终止正在运行或挂起的线程。我们可以使用如下的代码来终止线程:


代码如下:

1 thread.stop();

虽然使用上面的代码可以终止线程,但使用stop方法是很危险的,就象突然关闭计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果,因此,并不推荐使用stop方法来终止线程。

3. 使用interrupt方法终止线程

使用interrupt方法来终端线程可分为两种情况:

(1)线程处于阻塞状态,如使用了sleep方法。

(2)使用while(!isInterrupted()){……}来判断线程是否被中断。

在第一种情况下使用interrupt方法,sleep方法将抛出一个InterruptedException例外,而在第二种情况下线程将直接退出。下面的代码演示了在第一种情况下使用interrupt方法。


代码如下:

package chapter2;

public class ThreadInterrupt extends Thread
 {
     public void run()
     {
         try
         {
             sleep(50000);  // 延迟50秒
         }
         catch (InterruptedException e)
         {
             System.out.println(e.getMessage());
         }
     }
     public static void main(String[] args) throws Exception
     {
         Thread thread = new ThreadInterrupt();
         thread.start();
         System.out.println("在50秒之内按任意键中断线程!");
         System.in.read();
         thread.interrupt();
         thread.join();
         System.out.println("线程已经退出!");
     }
 }

上面代码的运行结果如下:


代码如下:

在50秒之内按任意键中断线程!

sleep interrupted
 线程已经退出!

在调用interrupt方法后, sleep方法抛出异常,然后输出错误信息:sleep interrupted.

注意:在Thread类中有两个方法可以判断线程是否通过interrupt方法被终止。一个是静态的方法interrupted(),一个是非静态的方法isInterrupted(),这两个方法的区别是interrupted用来判断当前线是否被中断,而isInterrupted可以用来判断其他线程是否被中断。因此,while (!isInterrupted())也可以换成while (!Thread.interrupted())。

(0)

相关推荐

  • 初步学习Java中线程的实现与生命周期

    线程的实现 在Java中通过run方法为线程指明要完成的任务,有两种技术来为线程提供run方法: 1.继承Thread类并重写它的run方法.之后创建这个子类的对象并调用start()方法. 2.通过定义实现Runnable接口的类进而实现run方法.这个类的对象在创建Thread的时候作为参数被传入,然后调用start()方法. Thread类是专门用来创建线程和对线程进行操作的类.当某个类继承了Thread类之后,该类就叫做一个线程类. 两种方法均需执行线程的start()方法为线程分配必须

  • Java 线程的生命周期详细介绍及实例代码

    当线程被创建并启动之后,它既不是一启动就进入执行状态,也不是一直处于执行状态,在其生命周期中,要经过"新建(New)"."就绪(Runnable)"."运行(Running')"."阻塞(Blocked)"和"死亡(Dead)"五种状态.线程在创建之后,不可能一直霸占着CPU独立运行,需要在多个线程之间切换,所以大部分时间处于运行.阻塞之间切换.  一.线程的状态 线程的存在有几种不同的状态,如下: New

  • java多线程编程之线程的生命周期

    复制代码 代码如下: // 开始线程public void start( );public void run( ); // 挂起和唤醒线程public void resume( ); // 不建议使用public void suspend( );// 不建议使用public static void sleep(long millis);public static void sleep(long millis, int nanos); // 终止线程public void stop( );   /

  • Java线程的生命周期和状态控制_动力节点Java学院整理

    一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(runnable). 注意:不能对已经启动的线程再次调用start()方法,否则会出现Javalang.IllegalThreadStateException异常. 2.就绪状态 处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线程就绪队列(尽管是采用队列形式,事实上,把它称

  • java 线程的生命周期详解

    一个线程的生命周期: 新建状态: 使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态.它保持这个状态直到程序 start() 这个线程. 就绪状态: 当线程对象调用了start()方法之后,该线程就进入就绪状态.就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度. 运行状态: 如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态.处于运行状态的线程最为复杂,它可以变为阻塞状态.就绪状态和死亡状态. 阻塞状态: 如

  • Java线程的生命周期的详解

    Java线程的生命周期的详解 对于多线程编程而言,理解线程的生命周期非常重要,本文就针对这一点进行讲解. 一.线程的状态 线程的存在有几种不同的状态,如下: New状态 Ready状态 Running状态 Dead状态 Non Runnable状态 1.New状态 New状态是线程已经被创建,但是还未开始运行的状态.此状态通过调用线程的start()方法可让线程运行. 2.Runnable状态 Runnable状态可称为准备运行状态,也可称为队列,此状态通过调用线程的start()方法可让线程运

  • 图解Java线程的生命周期

    在Java中,线程有5中不同状态,分别是:新建(New).就绪(Runable).运行(Running).阻塞(Blocked)和死亡(Dead).它们之间的转换图如下: 上图有一个例外,调用yield()方法可以让当前处于运行状态的线程转入就绪状态.如果要测试某线程是否已经死亡,可以使用isAlive()方法,该方法在线程处于就绪.运行.阻塞时放回true,新建和死亡时返回false.不要试图对一个已经死亡的线程调用start()方法而重新启动,死亡就是死亡和人一样,不可能再生.还有也不要对一

  • 深入探究Java线程的状态与生命周期

    目录 一.线程的状态 新建(初始) 就绪(可运行) 运行 阻塞 死亡 二.线程的状态转移 三.线程的生命周期 一.线程的状态 NEW: 安排了工作, 还未开始行动RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作.BLOCKED: 这几个都表示排队等着其他事情WAITING: 这几个都表示排队等着其他事情TIMED_WAITING: 这几个都表示排队等着其他事情TERMINATED: 工作完成了 新建(初始) 当继承Thread类和实现了Runnable接口,就可以创建线程,新建

  • C#多线程系列之线程的创建和生命周期

    目录 1,获取当前线程信息 2,管理线程状态 2.1 启动与参数传递 2.1.1 ParameterizedThreadStart 2.1.2 使用静态变量或类成员变量 2.1.3 委托与Lambda 2.2 暂停与阻塞 2.3 线程状态 2.4 终止 2.5 线程的不确定性 2.6 线程优先级.前台线程和后台线程 2.7 自旋和休眠 1,获取当前线程信息 Thread.CurrentThread 是一个 静态的 Thread 类,Thread 的CurrentThread 属性,可以获取到当前

  • Java 详解垃圾回收与对象生命周期

    Java 垃圾回收与对象生命周期详解 Java中的垃圾回收与对象生命周期 1. 垃圾回收 垃圾回收是Java程序设计中内存管理的核心概念,JVM的内存管理机制被称为垃圾回收机制. 一个对象创建后被放置在JVM的堆内存中,当永远不再引用这个对象时,它将被JVM在堆内存中回收.被创建的对象不能再生,同时也没有办法通过程序语句释放它们.即当对象在JVM运行空间中无法通过根集合到达(找到)时,这个对象被称为垃圾对象.根集合是由类中的静态引用域与本地引用域组成的.JVM通过根集合索引对象. 在做Java应

  • Java并发之线程池Executor框架的深入理解

    线程池 无限制的创建线程 若采用"为每个任务分配一个线程"的方式会存在一些缺陷,尤其是当需要创建大量线程时: 线程生命周期的开销非常高 资源消耗 稳定性 引入线程池 任务是一组逻辑工作单元,线程则是使任务异步执行的机制.当存在大量并发任务时,创建.销毁线程需要很大的开销,运用线程池可以大大减小开销. Executor框架 说明: Executor 执行器接口,该接口定义执行Runnable任务的方式. ExecutorService 该接口定义提供对Executor的服务. Sched

  • 深入讲解Java编程中类的生命周期

    引言         最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告诉你"怎样做",但至于"为什么这样做"却不多说,所以造成大家在基础和原理方面的知识比较匮乏,所以笔者今天就斗胆来讲一下这个问题,权当抛砖引玉,希望对在这个问题上有疑惑的朋友有所帮助,文中有说的不对的地方,也希望各路高手前来指正.         首先来了

  • Java对象在JVM中的生命周期详解

    概念 在Java中,对象的生命周期包括以下几个阶段: 创建阶段(Created) 应用阶段(In Use) 不可见阶段(Invisible) 不可达阶段(Unreachable) 收集阶段(Collected) 终结阶段(Finalized) 对象空间重分配阶段(De-allocated) Java对象在JVM中的生命周期 当你通过new语句创建一个java对象时,JVM就会为这个对象分配一块内存空间,只要这个对象被引用变量引用了,那么这个对象就会一直驻留在内存中,否则,它就会结束生命周期,JV

  • Android四大组件之Activity深入解读生命周期

    目录 一.什么是Activity 二.Activity之间的跳转 三.Activity 生命周期 3.1.Activity生命周期的基本状态 3.2.Activity 生命周期的7个方法 3.3.Activity 生命周期的三个循环 简介:在Android组件中最基本也是最为常见的四大组件: Activity Service服务 Content Provider内容提供者 BroadcastReceiver广播接收器 一.什么是Activity Activity是一个应用程序组件,提供一个屏幕,

随机推荐