守護線程總結

在Java中有兩類線程:User Thread(用戶線程)、Daemon Thread(守護線程) 

    Daemon的做用是爲其餘線程的運行提供便利服務,好比垃圾回收線程就是一個很稱職的守護者。User和Daemon二者幾乎沒有區別,惟一的不一樣之處就在於虛擬機的離開:若是 User Thread已經所有退出運行了,只剩下Daemon Thread存在了,虛擬機也就退出了。 由於沒有了被守護者,Daemon也就沒有工做可作了,也就沒有繼續運行程序的必要了。 

    值得一提的是,守護線程並不是只有虛擬機內部提供,用戶在編寫程序時也能夠本身設置守護線程。下面的方法就是用來設置守護線程的。 

    public final void setDaemon(boolean on) 

    這裏有幾點須要注意: 

    (1) thread.setDaemon(true)必須在thread.start()以前設置,不然會跑出一個IllegalThreadStateException異常。你不能把正在運行的常規線程設置爲守護線程。  
    (2) 在Daemon線程中產生的新線程也是Daemon的。  
    (3) 不要認爲全部的應用均可以分配給Daemon來進行服務,好比讀寫操做或者計算邏輯。 

       由於你不可能知道在全部的User完成以前,Daemon是否已經完成了預期的服務任務。一旦User退出了,可能大量數據尚未來得及讀入或寫出,計算任務也可能屢次運行結果不同。這對程序是毀滅性的。形成這個結果理由已經說過了:一旦全部User Thread離開了,虛擬機也就退出運行了。 

java

Java代碼  收藏代碼服務器

  1. //完成文件輸出的守護線程任務  多線程

  2. import java.io.*;     併發

  3.     

  4. class TestRunnable implements Runnable{     spa

  5.     public void run(){     線程

  6.                try{     code

  7.                   Thread.sleep(1000);//守護線程阻塞1秒後運行     server

  8.                   File f=new File("daemon.txt");     xml

  9.                   FileOutputStream os=new FileOutputStream(f,true);     blog

  10.                   os.write("daemon".getBytes());     

  11.            }     

  12.                catch(IOException e1){     

  13.           e1.printStackTrace();     

  14.                }     

  15.                catch(InterruptedException e2){     

  16.                   e2.printStackTrace();     

  17.            }     

  18.     }     

  19. }     

  20. public class TestDemo2{     

  21.     public static void main(String[] args) throws InterruptedException     

  22.     {     

  23.         Runnable tr=new TestRunnable();     

  24.         Thread thread=new Thread(tr);     

  25.                 thread.setDaemon(true); //設置守護線程     

  26.         thread.start(); //開始執行分進程     

  27.     }     

  28. }     

  29. //運行結果:文件daemon.txt中沒有"daemon"字符串。  



看到了吧,把輸入輸出邏輯包裝進守護線程多麼的可怕,字符串並無寫入指定文件。緣由也很簡單,直到主線程完成,守護線程仍處於1秒的阻塞狀態。這個時候主線程很快就運行完了,虛擬機退出,Daemon中止服務,輸出操做天然失敗了。 


例子2 : 

Java代碼  收藏代碼

  1. public class Test {  

  2.   public static void main(String args) {  

  3.   Thread t1 = new MyCommon();  

  4.   Thread t2 = new Thread(new MyDaemon());  

  5.   t2.setDaemon(true); //設置爲守護線程  

  6.   t2.start();  

  7.   t1.start();  

  8.   }  

  9.   }  

  10.   class MyCommon extends Thread {  

  11.   public void run() {  

  12.   for (int i = 0; i < 5; i++) {  

  13.   System.out.println("線程1第" + i + "次執行!");  

  14.   try {  

  15.   Thread.sleep(7);  

  16.   } catch (InterruptedException e) {  

  17.   e.printStackTrace();  

  18.   }  

  19.   }  

  20.   }  

  21.   }  


Java代碼  收藏代碼

  1. class MyDaemon implements Runnable {  

  2.   public void run() {  

  3.   for (long i = 0; i < 9999999L; i++) {  

  4.   System.out.println("後臺線程第" + i + "次執行!");  

  5.   try {  

  6.   Thread.sleep(7);  

  7.   } catch (InterruptedException e) {  

  8.   e.printStackTrace();  

  9.   }  

  10.   }  

  11.   }  

  12.   }  



後臺線程第0次執行! 
  線程1第0次執行! 
  線程1第1次執行! 
  後臺線程第1次執行! 
  後臺線程第2次執行! 
  線程1第2次執行! 
  線程1第3次執行! 
  後臺線程第3次執行! 
  線程1第4次執行! 
  後臺線程第4次執行! 
  後臺線程第5次執行! 
  後臺線程第6次執行! 
  後臺線程第7次執行! 
  Process finished with exit code 0 
  從上面的執行結果能夠看出: 
  前臺線程是保證執行完畢的,後臺線程尚未執行完畢就退出了。 
  實際上:JRE判斷程序是否執行結束的標準是全部的前臺執線程行完畢了,而無論後臺線程的狀態,所以,在使用後臺縣城時候必定要注意這個問題。 

實際應用例子:在使用長鏈接的comet服務端推送技術中,消息推送線程設置爲守護線程,服務於ChatServlet的servlet用戶線程,在servlet的init啓動消息線程,servlet一旦初始化後,一直存在服務器,servlet摧毀後,消息線程自動退出 

容器收到一個Servlet請求,調度線程從線程池中選出一個工做者線程,將請求傳遞給該工做者線程,而後由該線程來執行Servlet的 service方法。當這個線程正在執行的時候,容器收到另一個請求,調度線程一樣從線程池中選出另外一個工做者線程來服務新的請求,容器並不關心這個請求是否訪問的是同一個Servlet.當容器同時收到對同一個Servlet的多個請求的時候,那麼這個Servlet的service()方法將在多線程中併發執行。 
            Servlet容器默認採用單實例多線程的方式來處理請求,這樣減小產生Servlet實例的開銷,提高了對請求的響應時間,對於Tomcat能夠在server.xml中經過<Connector>元素設置線程池中線程的數目。 
如圖: 
 


爲何要用守護線程,見Web應用程序中調度器的啓動和關閉問題

相關文章
相關標籤/搜索