乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      java多線程-概念&創(chuàng)建啟動&中斷&守護線程&優(yōu)先級&線程狀態(tài)(多線程編程之一)

       沙門空海 2018-01-16

      多線程系列教程:

      java多線程-概念&創(chuàng)建啟動&中斷&守護線程&優(yōu)先級&線程狀態(tài)(多線程編程之一)
      java多線程同步以及線程間通信詳解&消費者生產(chǎn)者模式&死鎖&Thread.join()(多線程編程之二)
      java&android線程池-Executor框架之ThreadPoolExcutor&ScheduledThreadPoolExecutor淺析(多線程編程之三)
      Java多線程:Callable、Future和FutureTask淺析(多線程編程之四)

      今天開始就來總結(jié)一下java多線程的基礎(chǔ)知識點,下面是本篇的主要內(nèi)容(大部分知識點參考java核心技術(shù)卷1):

      1.什么是線程以及多線程與進程的區(qū)別
      2.多線程的創(chuàng)建與啟動
      3.中斷線程和守護線程以及線程優(yōu)先級
      4.線程的狀態(tài)轉(zhuǎn)化關(guān)系

      1.什么是線程以及多線程與進程的區(qū)別
              在現(xiàn)代操作在運行一個程序時,會為其創(chuàng)建一個進程。例如啟動一個QQ程序,操作系統(tǒng)就會為其創(chuàng)建一個進程。而操作系統(tǒng)中調(diào)度的最小單位元是線程,也叫輕量級進程,在一個進程里可以創(chuàng)建多個線程,這些線程都擁有各自的計數(shù)器,堆棧和局部變量等屬性,并且能夠訪問共享的內(nèi)存變量。處理器在這些線程上高速切換,讓使用者感覺到這些線程在同時執(zhí)行。因此我們可以這樣理解:
      進程:正在運行的程序,是系統(tǒng)進行資源分配和調(diào)用的獨立單位。每一個進程都有它自己的內(nèi)存空間和系統(tǒng)資源。
      線程:是進程中的單個順序控制流,是一條執(zhí)行路徑一個進程如果只有一條執(zhí)行路徑,則稱為單線程程序。一個進程如果有多條執(zhí)行路徑,則稱為多線程程序。

      2.多線程的創(chuàng)建與啟動
          創(chuàng)建多線程有兩種方法,一種是繼承Thread類重寫run方法,另一種是實現(xiàn)Runnable接口重寫run方法。下面我們分別給出代碼示例,繼承Thread類重寫run方法:
      1. package com.zejian.test;  
      2. /** 
      3.  * @author zejian 
      4.  * @time 2016年3月11日 下午9:57:44 
      5.  * @decrition 繼承Thread實現(xiàn)線程 
      6.  */  
      7. public class ThreadByEx extends Thread{  
      8.     /** 
      9.      * 重寫run方法 
      10.      */  
      11.     @Override  
      12.     public void run() {  
      13.         System.out.println("I'm a thread that extends Thread!");  
      14.     }  
      15. }  
      實現(xiàn)Runnable接口重寫run方法:
      1. package com.zejian.test;  
      2. /** 
      3.  * @author zejian 
      4.  * @time 2016年3月11日 下午10:00:36 
      5.  * @decrition 實現(xiàn)Runnable接口重寫run方法 
      6.  */  
      7. public class ThreadByRunnable implements Runnable{  
      8.     /** 
      9.      * 實現(xiàn)run方法 
      10.      */  
      11.     @Override  
      12.     public void run() {  
      13.         System.out.println("I'm a thread that implements Runnable !");  
      14.     }  
      15. }  
      怎么啟動線程?
      1. package com.zejian.test;  
      2. public class MainTest {  
      3.       
      4.     public static void main(String[] args) {  
      5.         //繼承Thread啟動的方法  
      6.         ThreadByEx t1=new ThreadByEx();  
      7.         t1.start();//啟動線程  
      8.           
      9.           
      10.         //實現(xiàn)Runnable啟動線程的方法  
      11.         ThreadByRunnable r = new ThreadByRunnable();  
      12.         Thread t2 =new Thread(r);  
      13.         t2.start();//啟動線程  
      14.     }  
      15. }  
      運行結(jié)果:
      1. I'm a thread that extends Thread!  
      2. I'm a thread that implements Runnable !  
      代碼相當簡單,不過多解釋。這里有點需要注意的是調(diào)用start()方法后并不是是立即的執(zhí)行多線程的代碼,而是使該線程變?yōu)榭蛇\行態(tài),什么時候運行多線程代碼是由操作系統(tǒng)決定的。

      3.中斷線程和守護線程以及線程優(yōu)先級
      什么是中斷線程?
      我們先來看看中斷線程是什么?(該解釋來自java核心技術(shù)一書,我對其進行稍微簡化),當線程的run()方法執(zhí)行方法體中的最后一條語句后,并經(jīng)由執(zhí)行return語句返回時,或者出現(xiàn)在方法中沒有捕獲的異常時線程將終止。在java早期版本中有一個stop方法,其他線程可以調(diào)用它終止線程,但是這個方法現(xiàn)在已經(jīng)被棄用了,因為這個方法會造成一些線程不安全的問題。我們可以把中斷理解為一個標識位的屬性,它表示一個運行中的線程是否被其他線程進行了中斷操作,而中斷就好比其他線程對該線程打可個招呼,其他線程通過調(diào)用該線程的interrupt方法對其進行中斷操作,當一個線程調(diào)用interrupt方法時,線程的中斷狀態(tài)(標識位)將被置位(改變),這是每個線程都具有的boolean標志,每個線程都應(yīng)該不時的檢查這個標志,來判斷線程是否被中斷。而要判斷線程是否被中斷,我們可以使用如下代碼
      1. Thread.currentThread().isInterrupted()  
      1. while(!Thread.currentThread().isInterrupted()){  
      2.     do something  
      3. }  
      但是如果此時線程處于阻塞狀態(tài)(sleep或者wait),就無法檢查中斷狀態(tài),此時會拋出InterruptedException異常。如果每次迭代之后都調(diào)用sleep方法(或者其他可中斷的方法),isInterrupted檢測就沒必要也沒用處了,如果在中斷狀態(tài)被置位時調(diào)用sleep方法,它不會休眠反而會清除這一休眠狀態(tài)并拋出InterruptedException。所以如果在循環(huán)中調(diào)用sleep,不要去檢測中斷狀態(tài),只需捕獲InterruptedException。代碼范例如下:
      1. public void run(){  
      2.         while(more work to do ){  
      3.             try {  
      4.                 Thread.sleep(5000);  
      5.             } catch (InterruptedException e) {  
      6.                 //thread was interrupted during sleep  
      7.                 e.printStackTrace();  
      8.             }finally{  
      9.                 //clean up , if required  
      10.             }  
      11.         }  
      同時還有點要注意的就是我們在捉中斷異常時盡量按如下形式處理,不要留空白什么都不處理!
      不妥的處理方式:
      1. void myTask(){  
      2.     ...  
      3.    try{  
      4.        sleep(50)  
      5.       }catch(InterruptedException e){  
      6.    ...  
      7.    }  
      8. }  
      正確的處理方式:
      1. void myTask()throw InterruptedException{  
      2.     sleep(50)  
      3. }  
      或者
      1. void myTask(){  
      2.     ...  
      3.     try{  
      4.     sleep(50)  
      5.     }catch(InterruptedException e){  
      6.      Thread.currentThread().interrupt();  
      7.     }  
      8. }  
      最后關(guān)于中斷線程,我們這里給出中斷線程的一些主要方法:
      void interrupt():向線程發(fā)送中斷請求,線程的中斷狀態(tài)將會被設(shè)置為true,如果當前線程被一個sleep調(diào)用阻塞,那么將會拋出interrupedException異常。
      static boolean interrupted():測試當前線程(當前正在執(zhí)行命令的這個線程)是否被中斷。注意這是個靜態(tài)方法,調(diào)用這個方法會產(chǎn)生一個副作用那就是它會將當前線程的中斷狀態(tài)重置為false。
      boolean isInterrupted():判斷線程是否被中斷,這個方法的調(diào)用不會產(chǎn)生副作用即不改變線程的當前中斷狀態(tài)。
      static Thread currentThread() : 返回代表當前執(zhí)行線程的Thread對象。
      什么是守護線程?
      首先我們可以通過t.setDaemon(true)的方法將線程轉(zhuǎn)化為守護線程。而守護線程的唯一作用就是為其他線程提供服務(wù)。計時線程就是一個典型的例子,它定時地發(fā)送“計時器滴答”信號告訴其他線程去執(zhí)行某項任務(wù)。當只剩下守護線程時,虛擬機就退出了,因為如果只剩下守護線程,程序就沒有必要執(zhí)行了。另外JVM的垃圾回收、內(nèi)存管理等線程都是守護線程。還有就是在做數(shù)據(jù)庫應(yīng)用時候,使用的數(shù)據(jù)庫連接池,連接池本身也包含著很多后臺線程,監(jiān)控連接個數(shù)、超時時間、狀態(tài)等等。最后還有一點需要特別注意的是在java虛擬機退出時Daemon線程中的finally代碼塊并不一定會執(zhí)行哦,代碼示例:
      1. package com.zejian.test;  
      2. /** 
      3.  * @author zejian 
      4.  * @time 2016年3月12日 上午10:42:19 
      5.  * @decrition 守護線程代碼示例 
      6.  */  
      7. public class Demon {  
      8.     public static void main(String[] args) {  
      9.         Thread deamon = new Thread(new DaemonRunner(),"DaemonRunner");  
      10.         //設(shè)置為守護線程  
      11.         deamon.setDaemon(true);  
      12.         deamon.start();//啟動線程  
      13.     }  
      14.       
      15.       
      16.     static class DaemonRunner implements Runnable{  
      17.         @Override  
      18.         public void run() {  
      19.             try {  
      20.                 Thread.sleep(500);  
      21.             } catch (InterruptedException e) {  
      22.                 e.printStackTrace();  
      23.             }finally{  
      24.                 System.out.println("這里的代碼在java虛擬機退出時并不一定會執(zhí)行哦!");  
      25.             }  
      26.         }  
      27.     }  
      28. }  
      因此在構(gòu)建Daemon線程時,不能依靠finally代碼塊中的內(nèi)容來確保執(zhí)行關(guān)閉或清理資源的邏輯。
      什么是線程優(yōu)先級
              在現(xiàn)代操作系統(tǒng)中基本采用時分的形式調(diào)度運行的線程,操作系統(tǒng)會分出一個個時間片,線程會分配到若干時間片,當線程的時間片用完了就會發(fā)生線程調(diào)度,并等待著下一次分配。線程分配到的時間片多少也決定了線程使用處理器資源的多少,而線程優(yōu)先級就是決定線程需要多或者少分配一些處理器資源的線程屬性。在java線程中,通過一個整型的成員變量Priority來控制線程優(yōu)先級,每一個線程有一個優(yōu)先級,默認情況下,一個線程繼承它父類的優(yōu)先級??梢杂胹etPriority方法提高或降低任何一個線程優(yōu)先級??梢詫?yōu)先級設(shè)置在MIN_PRIORITY(在Thread類定義為1)與MAX_PRIORITY(在Thread類定義為10)之間的任何值。線程的默認優(yōu)先級為NORM_PRIORITY(在Thread類定義為5)。盡量不要依賴優(yōu)先級,如果確實要用,應(yīng)該避免初學(xué)者常犯的一個錯誤。如果有幾個高優(yōu)先級的線程沒有進入非活動狀態(tài),低優(yōu)先級線程可能永遠也不能執(zhí)行。每當調(diào)度器決定運行一個新線程時,首先會在具有高優(yōu)先級的線程中進行選擇,盡管這樣會使低優(yōu)先級的線程可能永遠不會被執(zhí)行到。因此我們在設(shè)置優(yōu)先級時,針對頻繁阻塞(休眠或者I/O操作)的線程需要設(shè)置較高的優(yōu)先級,而偏重計算(需要較多CPU時間或者運算)的線程則設(shè)置較低的優(yōu)先級,這樣才能確保處理器不會被長久獨占。當然還有要注意就是在不同的JVM以及操作系統(tǒng)上線程的規(guī)劃存在差異,有些操作系統(tǒng)甚至?xí)雎詫€程優(yōu)先級的設(shè)定,如mac os系統(tǒng)或者Ubuntu系統(tǒng)........

      4.線程的狀態(tài)轉(zhuǎn)化關(guān)系
      (1). 新建狀態(tài)(New):新創(chuàng)建了一個線程對象。
      (2). 就緒狀態(tài)(Runnable):線程對象創(chuàng)建后,其他線程調(diào)用了該對象的start()方法。該狀態(tài)的線程位于可運行線程池中,變得可運行,等待獲取CPU的使用權(quán)。
      (3). 運行狀態(tài)(Running):就緒狀態(tài)的線程獲取了CPU,執(zhí)行程序代碼。
      (4). 阻塞狀態(tài)(Blocked):阻塞狀態(tài)是線程因為某種原因放棄CPU使用權(quán),暫時停止運行。直到線程進入就緒狀態(tài),才有機會轉(zhuǎn)到運行狀態(tài)。阻塞的情況分三種:

      - 等待阻塞(WAITING):運行的線程執(zhí)行wait()方法,JVM會把該線程放入等待池中。

      - 同步阻塞(Blocked):運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程占用,則JVM會把該線程放入鎖池中。

      - 超時阻塞(TIME_WAITING):運行的線程執(zhí)行sleep(long)或join(long)方法,或者發(fā)出了I/O請求時,JVM會把該線程置為阻塞狀態(tài)。

      (5). 死亡狀態(tài)(Dead):線程執(zhí)行完了或者因異常退出了run()方法,該線程結(jié)束生命周期。



      圖中的方法解析如下:
      Thread.sleep():在指定時間內(nèi)讓當前正在執(zhí)行的線程暫停執(zhí)行,但不會釋放"鎖標志"。不推薦使用。
      Thread.sleep(long):使當前線程進入阻塞狀態(tài),在指定時間內(nèi)不會執(zhí)行。 
      Object.wait()和Object.wait(long):在其他線程調(diào)用對象的notify或notifyAll方法前,導(dǎo)致當前線程等待。線程會釋放掉它所占有的"鎖標志",從而使別的線程有機會搶占該鎖。 當前線程必須擁有當前對象鎖。如果當前線程不是此鎖的擁有者,會拋出IllegalMonitorStateException異常。 喚醒當前對象鎖的等待線程使用notify或notifyAll方法,也必須擁有相同的對象鎖,否則也會拋出IllegalMonitorStateException異常,waite()和notify()必須在synchronized函數(shù)或synchronized中進行調(diào)用。如果在non-synchronized函數(shù)或non-synchronized中進行調(diào)用,雖然能編譯通過,但在運行時會發(fā)生IllegalMonitorStateException的異常。 
      Object.notifyAll():則從對象等待池中喚醒所有等待等待線程
      Object.notify():則從對象等待池中喚醒其中一個線程。
      Thread.yield()方法 暫停當前正在執(zhí)行的線程對象,yield()只是使當前線程重新回到可執(zhí)行狀態(tài),所以執(zhí)行yield()的線程有可能在進入到可執(zhí)行狀態(tài)后馬上又被執(zhí)行,yield()只能使同優(yōu)先級或更高優(yōu)先級的線程有執(zhí)行的機會。 
      Thread.Join():把指定的線程加入到當前線程,可以將兩個交替執(zhí)行的線程合并為順序執(zhí)行的線程。比如在線程B中調(diào)用了線程A的Join()方法,直到線程A執(zhí)行完畢后,才會繼續(xù)執(zhí)行線程B。
      好了。本篇線程基礎(chǔ)知識介紹到此結(jié)束。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多