首頁  >  文章  >  Java  >  java線程之線程的生命週期的使用

java線程之線程的生命週期的使用

黄舟
黄舟原創
2016-12-19 14:37:141373瀏覽

與人有生老病死一樣,線程也同樣要經歷開始(等待)、運行、掛起和停止四種不同的狀態。這四種狀態都可以透過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())。


 以上就是java线程之线程的生命周期的使用的内容,更多相关内容请关注PHP中文网(www.php.cn)! 


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn