欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java守護(hù)線程實(shí)例詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

 更新時(shí)間:2017年06月02日 14:36:00   投稿:mrr  
在Java中有兩類線程:User Thread(用戶線程)、Daemon Thread(守護(hù)線程) 。下面通過(guò)本文給大家分享java守護(hù)線程實(shí)例詳解,需要的朋友參考下吧

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

用個(gè)比較通俗的比如,任何一個(gè)守護(hù)線程都是整個(gè)JVM中所有非守護(hù)線程的保姆:

只要當(dāng)前JVM實(shí)例中尚存在任何一個(gè)非守護(hù)線程沒(méi)有結(jié)束,守護(hù)線程就全部工作;只有當(dāng)最后一個(gè)非守護(hù)線程結(jié)束時(shí),守護(hù)線程隨著JVM一同結(jié)束工作。

Daemon的作用是為其他線程的運(yùn)行提供便利服務(wù),守護(hù)線程最典型的應(yīng)用就是 GC (垃圾回收器),它就是一個(gè)很稱職的守護(hù)者。

User和Daemon兩者幾乎沒(méi)有區(qū)別,唯一的不同之處就在于虛擬機(jī)的離開(kāi):如果 User Thread已經(jīng)全部退出運(yùn)行了,只剩下Daemon Thread存在了,虛擬機(jī)也就退出了。 因?yàn)闆](méi)有了被守護(hù)者,Daemon也就沒(méi)有工作可做了,也就沒(méi)有繼續(xù)運(yùn)行程序的必要了。

值得一提的是,守護(hù)線程并非只有虛擬機(jī)內(nèi)部提供,用戶在編寫程序時(shí)也可以自己設(shè)置守護(hù)線程。下面的方法就是用來(lái)設(shè)置守護(hù)線程的。 

Thread daemonTread = new Thread(); 
 // 設(shè)定 daemonThread 為 守護(hù)線程,default false(非守護(hù)線程) 
 daemonThread.setDaemon(true); 
 // 驗(yàn)證當(dāng)前線程是否為守護(hù)線程,返回 true 則為守護(hù)線程 
 daemonThread.isDaemon(); 

這里有幾點(diǎn)需要注意: 

(1) thread.setDaemon(true)必須在thread.start()之前設(shè)置,否則會(huì)跑出一個(gè)IllegalThreadStateException異常。你不能把正在運(yùn)行的常規(guī)線程設(shè)置為守護(hù)線程。

(2) 在Daemon線程中產(chǎn)生的新線程也是Daemon的。 

(3) 不要認(rèn)為所有的應(yīng)用都可以分配給Daemon來(lái)進(jìn)行服務(wù),比如讀寫操作或者計(jì)算邏輯。 

因?yàn)槟悴豢赡苤涝谒械腢ser完成之前,Daemon是否已經(jīng)完成了預(yù)期的服務(wù)任務(wù)。一旦User退出了,可能大量數(shù)據(jù)還沒(méi)有來(lái)得及讀入或?qū)懗觯?jì)算任務(wù)也可能多次運(yùn)行結(jié)果不一樣。這對(duì)程序是毀滅性的。造成這個(gè)結(jié)果理由已經(jīng)說(shuō)過(guò)了:一旦所有User Thread離開(kāi)了,虛擬機(jī)也就退出運(yùn)行了。 

//完成文件輸出的守護(hù)線程任務(wù) 
import java.io.*;  
class TestRunnable implements Runnable{  
 public void run(){  
    try{  
     Thread.sleep(1000);//守護(hù)線程阻塞1秒后運(yùn)行  
     File f=new File("daemon.txt");  
     FileOutputStream os=new FileOutputStream(f,true);  
     os.write("daemon".getBytes());  
   }  
    catch(IOException e1){  
   e1.printStackTrace();  
    }  
    catch(InterruptedException e2){  
     e2.printStackTrace();  
   }  
 }  
}  
public class TestDemo2{  
 public static void main(String[] args) throws InterruptedException  
 {  
  Runnable tr=new TestRunnable();  
  Thread thread=new Thread(tr);  
    thread.setDaemon(true); //設(shè)置守護(hù)線程  
  thread.start(); //開(kāi)始執(zhí)行分進(jìn)程  
 }  
}  
//運(yùn)行結(jié)果:文件daemon.txt中沒(méi)有"daemon"字符串。 

看到了吧,把輸入輸出邏輯包裝進(jìn)守護(hù)線程多么的可怕,字符串并沒(méi)有寫入指定文件。原因也很簡(jiǎn)單,直到主線程完成,守護(hù)線程仍處于1秒的阻塞狀態(tài)。這個(gè)時(shí)候主線程很快就運(yùn)行完了,虛擬機(jī)退出,Daemon停止服務(wù),輸出操作自然失敗了。

public class Test { 
  public static void main(String args) { 
  Thread t1 = new MyCommon(); 
  Thread t2 = new Thread(new MyDaemon()); 
  t2.setDaemon(true); //設(shè)置為守護(hù)線程 
  t2.start(); 
  t1.start(); 
  } 
  } 
  class MyCommon extends Thread { 
  public void run() { 
  for (int i = 0; i < 5; i++) { 
  System.out.println("線程1第" + i + "次執(zhí)行!"); 
  try { 
  Thread.sleep(7); 
  } catch (InterruptedException e) { 
  e.printStackTrace(); 
  } 
  } 
  } 
  } 
class MyDaemon implements Runnable { 
  public void run() { 
  for (long i = 0; i < 9999999L; i++) { 
  System.out.println("后臺(tái)線程第" + i + "次執(zhí)行!"); 
  try { 
  Thread.sleep(7); 
  } catch (InterruptedException e) { 
  e.printStackTrace(); 
  } 
  } 
  } 
  } 

后臺(tái)線程第0次執(zhí)行!
  線程1第0次執(zhí)行! 
  線程1第1次執(zhí)行! 
  后臺(tái)線程第1次執(zhí)行! 
  后臺(tái)線程第2次執(zhí)行! 
  線程1第2次執(zhí)行! 
  線程1第3次執(zhí)行! 
  后臺(tái)線程第3次執(zhí)行! 
  線程1第4次執(zhí)行! 
  后臺(tái)線程第4次執(zhí)行! 
  后臺(tái)線程第5次執(zhí)行! 
  后臺(tái)線程第6次執(zhí)行! 
  后臺(tái)線程第7次執(zhí)行! 
  Process finished with exit code 0 

  從上面的執(zhí)行結(jié)果可以看出: 

  前臺(tái)線程是保證執(zhí)行完畢的,后臺(tái)線程還沒(méi)有執(zhí)行完畢就退出了。 

  實(shí)際上:JRE判斷程序是否執(zhí)行結(jié)束的標(biāo)準(zhǔn)是所有的前臺(tái)執(zhí)線程行完畢了,而不管后臺(tái)線程的狀態(tài),因此,在使用后臺(tái)線程時(shí)候一定要注意這個(gè)問(wèn)題。 

補(bǔ)充說(shuō)明:

定義:守護(hù)線程--也稱“服務(wù)線程”,在沒(méi)有用戶線程可服務(wù)時(shí)會(huì)自動(dòng)離開(kāi)。

優(yōu)先級(jí):守護(hù)線程的優(yōu)先級(jí)比較低,用于為系統(tǒng)中的其它對(duì)象和線程提供服務(wù)。

設(shè)置:通過(guò)setDaemon(true)來(lái)設(shè)置線程為“守護(hù)線程”;將一個(gè)用戶線程設(shè)置為守護(hù)線程的方式是在 線程對(duì)象創(chuàng)建 之前 用線程對(duì)象的setDaemon方法。

example: 垃圾回收線程就是一個(gè)經(jīng)典的守護(hù)線程,當(dāng)我們的程序中不再有任何運(yùn)行的Thread,程序就不會(huì)再產(chǎn)生垃圾,垃圾回收器也就無(wú)事可做,所以當(dāng)垃圾回收線程是JVM上僅剩的線程時(shí),垃圾回收線程會(huì)自動(dòng)離開(kāi)。它始終在低級(jí)別的狀態(tài)中運(yùn)行,用于實(shí)時(shí)監(jiān)控和管理系統(tǒng)中的可回收資源。

生命周期:守護(hù)進(jìn)程(Daemon)是運(yùn)行在后臺(tái)的一種特殊進(jìn)程。它獨(dú)立于控制終端并且周期性地執(zhí)行某種任務(wù)或等待處理某些發(fā)生的事件。也就是說(shuō)守護(hù)線程不依賴于終端,但是依賴于系統(tǒng),與系統(tǒng)“同生共死”。那Java的守護(hù)線程是什么樣子的呢。當(dāng)JVM中所有的線程都是守護(hù)線程的時(shí)候,JVM就可以退出了;如果還有一個(gè)
或以上的非守護(hù)線程則JVM不會(huì)退出。

實(shí)際應(yīng)用例子:

在使用長(zhǎng)連接的comet服務(wù)端推送技術(shù)中,消息推送線程設(shè)置為守護(hù)線程,服務(wù)于ChatServlet的servlet用戶線程,在servlet的init啟動(dòng)消息線程,servlet一旦初始化后,一直存在服務(wù)器,servlet摧毀后,消息線程自動(dòng)退出

容器收到一個(gè)Servlet請(qǐng)求,調(diào)度線程從線程池中選出一個(gè)工作者線程,將請(qǐng)求傳遞給該工作者線程,然后由該線程來(lái)執(zhí)行Servlet的 service方法。當(dāng)這個(gè)線程正在執(zhí)行的時(shí)候,容器收到另外一個(gè)請(qǐng)求,調(diào)度線程同樣從線程池中選出另一個(gè)工作者線程來(lái)服務(wù)新的請(qǐng)求,容器并不關(guān)心這個(gè)請(qǐng)求是否訪問(wèn)的是同一個(gè)Servlet.當(dāng)容器同時(shí)收到對(duì)同一個(gè)Servlet的多個(gè)請(qǐng)求的時(shí)候,那么這個(gè)Servlet的service()方法將在多線程中并發(fā)執(zhí)行。

Servlet容器默認(rèn)采用單實(shí)例多線程的方式來(lái)處理請(qǐng)求,這樣減少產(chǎn)生Servlet實(shí)例的開(kāi)銷,提升了對(duì)請(qǐng)求的響應(yīng)時(shí)間,對(duì)于Tomcat可以在server.xml中通過(guò)<Connector>元素設(shè)置線程池中線程的數(shù)目。
如圖: 

為什么要用守護(hù)線程?

我們知道靜態(tài)變量是ClassLoader級(jí)別的,如果Web應(yīng)用程序停止,這些靜態(tài)變量也會(huì)從JVM中清除。但是線程則是JVM級(jí)別的,如果你在Web 應(yīng)用中啟動(dòng)一個(gè)線程,這個(gè)線程的生命周期并不會(huì)和Web應(yīng)用程序保持同步。也就是說(shuō),即使你停止了Web應(yīng)用,這個(gè)線程依舊是活躍的。正是因?yàn)檫@個(gè)很隱晦 的問(wèn)題,所以很多有經(jīng)驗(yàn)的開(kāi)發(fā)者不太贊成在Web應(yīng)用中私自啟動(dòng)線程。

如果我們手工使用JDK Timer(Quartz的Scheduler),在Web容器啟動(dòng)時(shí)啟動(dòng)Timer,當(dāng)Web容器關(guān)閉時(shí),除非你手工關(guān)閉這個(gè)Timer,否則Timer中的任務(wù)還會(huì)繼續(xù)運(yùn)行!

下面通過(guò)一個(gè)小例子來(lái)演示這個(gè)“詭異”的現(xiàn)象,我們通過(guò)ServletContextListener在Web容器啟動(dòng)時(shí)創(chuàng)建一個(gè)Timer并周期性地運(yùn)行一個(gè)任務(wù):

//代碼清單StartCycleRunTask:容器監(jiān)聽(tīng)器 
package com.bjpowernode.web; 
import java.util.Date; 
import java.util.Timer; 
import java.util.TimerTask; 
import javax.servlet.ServletContextEvent; 
import javax.servlet.ServletContextListener; 
public class StartCycleRunTask implements ServletContextListener ...{ 
 private Timer timer; 
 public void contextDestroyed(ServletContextEvent arg0) ...{ 
  // ②該方法在Web容器關(guān)閉時(shí)執(zhí)行 
  System.out.println("Web應(yīng)用程序啟動(dòng)關(guān)閉..."); 
 } 
 public void contextInitialized(ServletContextEvent arg0) ...{ 
   //②在Web容器啟動(dòng)時(shí)自動(dòng)執(zhí)行該方法 
  System.out.println("Web應(yīng)用程序啟動(dòng)..."); 
  timer = new Timer();//②-1:創(chuàng)建一個(gè)Timer,Timer內(nèi)部自動(dòng)創(chuàng)建一個(gè)背景線程 
  TimerTask task = new SimpleTimerTask(); 
  timer.schedule(task, 1000L, 5000L); //②-2:注冊(cè)一個(gè)5秒鐘運(yùn)行一次的任務(wù) 
 } 
} 
class SimpleTimerTask extends TimerTask ...{//③任務(wù) 
 private int count; 
 public void run() ...{ 
  System.out.println((++count)+"execute task..."+(new Date())); 
 } 
} 

在web.xml中聲明這個(gè)Web容器監(jiān)聽(tīng)器:

<?xml version="1.0" encoding="UTF-8"?>
<web-app> 
… 
<listener> 
<listener-class>com.bjpowernode.web.StartCycleRunTask</listener-class> 
</listener> 
</web-app> 

在Tomcat中部署這個(gè)Web應(yīng)用并啟動(dòng)后,你將看到任務(wù)每隔5秒鐘執(zhí)行一次。 

運(yùn)行一段時(shí)間后,登錄Tomcat管理后臺(tái),將對(duì)應(yīng)的Web應(yīng)用(chapter13)關(guān)閉。 

轉(zhuǎn)到Tomcat控制臺(tái),你將看到雖然Web應(yīng)用已經(jīng)關(guān)閉,但Timer任務(wù)還在我行我素地執(zhí)行如故——舞臺(tái)已經(jīng)拆除,戲子繼續(xù)表演: 

我們可以通過(guò)改變清單StartCycleRunTask的代碼,在contextDestroyed(ServletContextEvent arg0)中添加timer.cancel()代碼,在Web容器關(guān)閉后手工停止Timer來(lái)結(jié)束任務(wù)。

Spring為JDK Timer和Quartz Scheduler所提供的TimerFactoryBean和SchedulerFactoryBean能夠和Spring容器的生命周期關(guān)聯(lián),在 Spring容器啟動(dòng)時(shí)啟動(dòng)調(diào)度器,而在Spring容器關(guān)閉時(shí),停止調(diào)度器。所以在Spring中通過(guò)這兩個(gè)FactoryBean配置調(diào)度器,再?gòu)?Spring IoC中獲取調(diào)度器引用進(jìn)行任務(wù)調(diào)度將不會(huì)出現(xiàn)這種Web容器關(guān)閉而任務(wù)依然運(yùn)行的問(wèn)題。而如果你在程序中直接使用Timer或Scheduler,如不 進(jìn)行額外的處理,將會(huì)出現(xiàn)這一問(wèn)題。 

相關(guān)文章

  • RateLimiter 源碼分析

    RateLimiter 源碼分析

    本文主要對(duì)ratelimiter的常用方法以及源碼進(jìn)行了分析解讀,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-09-09
  • 解讀@EventListener工作原理

    解讀@EventListener工作原理

    這篇文章主要介紹了@EventListener工作原理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 如何使用GSON解析JSON數(shù)據(jù)

    如何使用GSON解析JSON數(shù)據(jù)

    這篇文章主要介紹了如何使用GSON解析JSON數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Springboot中如何自定義監(jiān)聽(tīng)器

    Springboot中如何自定義監(jiān)聽(tīng)器

    這篇文章主要介紹了Springboot中自定義監(jiān)聽(tīng)器,自定義事件需要繼承ApplicationEvent類,并添加一個(gè)構(gòu)造函數(shù),用于接收事件源對(duì)象,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2024-07-07
  • Java?API文檔的使用方法詳解

    Java?API文檔的使用方法詳解

    在開(kāi)發(fā)過(guò)程中如果遇到疑難問(wèn)題,除了可以在網(wǎng)絡(luò)中尋找答案,也可以在Java API幫助文檔(簡(jiǎn)稱"JDK文檔"”)中查找答案,下面這篇文章主要給大家介紹了關(guān)于Java?API文檔使用的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • Java中反射reflect的基礎(chǔ)知識(shí)講解

    Java中反射reflect的基礎(chǔ)知識(shí)講解

    這篇文章主要介紹了Java中反射reflect的基礎(chǔ)知識(shí)講解,Java中的反射,它算是Java當(dāng)中非常底層的一個(gè)技術(shù),平時(shí)我們我們用得不多,實(shí)際上它也的確非常復(fù)雜同時(shí)也難以理解,但是涉及到底層的東西Java都給我們封裝好了,我們直接拿來(lái)調(diào)用即可,需要的朋友可以參考下
    2023-10-10
  • IDEA的基本使用(讓你的IDEA有飛一般的感覺(jué))

    IDEA的基本使用(讓你的IDEA有飛一般的感覺(jué))

    這篇文章主要介紹了IDEA的基本使用(讓你的IDEA有飛一般的感覺(jué)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Java監(jiān)聽(tīng)器ActionListener與MouseListener的執(zhí)行順序說(shuō)明

    Java監(jiān)聽(tīng)器ActionListener與MouseListener的執(zhí)行順序說(shuō)明

    這篇文章主要介紹了Java監(jiān)聽(tīng)器ActionListener與MouseListener的執(zhí)行順序說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Springboot整合Mybatispuls的實(shí)例詳解

    Springboot整合Mybatispuls的實(shí)例詳解

    這篇文章主要介紹了Springboot整合Mybatispuls的相關(guān)資料,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Mybatis-Plus支持GBase8s分頁(yè)查詢的實(shí)現(xiàn)示例

    Mybatis-Plus支持GBase8s分頁(yè)查詢的實(shí)現(xiàn)示例

    本文主要介紹了使?Mybatis-Plus?支持?GBase8s?的分頁(yè)查詢,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01

最新評(píng)論