日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

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

 沙門空海 2018-01-16

多線程系列教程:

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

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

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

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

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

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

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

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

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

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

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



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

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多