JavaSE入门学习50:多线程编程(一)
一進(jìn)程和線程
? ? ? ??(1)進(jìn)程和線程的基本概念
? ? ? ? 進(jìn)程:程序(任務(wù))的執(zhí)行過(guò)程;持有資源(共享內(nèi)存,共享文件)和線程。
? ? ? ? 線程:是一個(gè)程序內(nèi)部的順序控制流。
? ? ? ? 我們生活中的進(jìn)程例子很多,一個(gè)進(jìn)程就相當(dāng)于一個(gè)你在電腦上啟動(dòng)的程序。比如我們打開(kāi)最常用的聊天工具
QQ,也可以打開(kāi)Java的開(kāi)發(fā)工具Eclipse等等。這些都算Window操作系統(tǒng)上的一個(gè)進(jìn)程。
? ? ? ? 對(duì)于Window操作系統(tǒng)上一個(gè)線程,還是拿QQ進(jìn)程和Eclipse進(jìn)程來(lái)舉例,QQ進(jìn)程中的文字聊天和收發(fā)文件就是
其中的兩個(gè)線程;Eclipse進(jìn)程中的源代碼文件編輯、源代碼編譯和語(yǔ)法校驗(yàn)就是其中的三個(gè)線程。
? ? ? ? 通過(guò)上面的知識(shí)可以得出:?? ? ? ? ? ? ? ? ? ??
? ? ? ? 1)一個(gè)進(jìn)程可以有多個(gè)線程;
? ? ? ? 2)線程是系統(tǒng)中最小的執(zhí)行單元;
? ? ? ? 3)同一進(jìn)程中有多個(gè)線程;
? ? ? ? 4)線程共享進(jìn)程的資源。
? ? ? ??(2)線程和進(jìn)程的區(qū)別
? ? ? ? 每個(gè)進(jìn)程都有獨(dú)立的代碼和數(shù)據(jù)空間(進(jìn)行上下文),進(jìn)程間的切換會(huì)有較大的開(kāi)銷(xiāo)。多進(jìn)程指的是在操作系統(tǒng)中
同時(shí)運(yùn)行多個(gè)任務(wù)(程序)。
? ? ? ?線程可以看成輕量級(jí)的進(jìn)程,同一類(lèi)線程共享代碼和數(shù)據(jù)空間,每個(gè)線程有獨(dú)立的運(yùn)行棧和程序計(jì)數(shù)器(PC),線
程切換的開(kāi)銷(xiāo)小。多線程指的是在同一程序中有多個(gè)順序流相同時(shí)執(zhí)行。
? ? ? ?(3)線程交互
? ? ? ?線程間的通信包括互斥和同步。
? ? ? ?互斥:通常表現(xiàn)在多個(gè)線程競(jìng)爭(zhēng)同一資源,比如這里只有一只筆,同時(shí)有幾個(gè)人要進(jìn)行簽到,但資源(筆)唯一,
線程(人)之間就存在競(jìng)爭(zhēng)關(guān)系,并且同一時(shí)間只有一個(gè)線程(人)能夠持有這個(gè)資(筆)。
? ? ? ?同步:同步就是協(xié)同步調(diào),按預(yù)定的先后次序進(jìn)行運(yùn)行,如進(jìn)程、線程同步,可理解為進(jìn)程或線程A和B一塊配
合,A執(zhí)行到一定程度時(shí)要依靠B的某個(gè)結(jié)果,于是停下來(lái),示意B運(yùn)行;B依言執(zhí)行,再將結(jié)果給A;A再繼續(xù)操作。
? ? ? ?二Java多線程
? ? ? ?Java多線程是通過(guò)java.lang.Thread類(lèi)來(lái)實(shí)現(xiàn)的。VM啟動(dòng)時(shí)會(huì)有一個(gè)由主方法(public static void main(){})所定義
的線程。可以通過(guò)創(chuàng)建Thread類(lèi)的實(shí)例來(lái)創(chuàng)建新的線程。每個(gè)線程都是通過(guò)某個(gè)特定Thread類(lèi)的對(duì)象所對(duì)應(yīng)的方法
run()來(lái)完成其操作的,方法run()稱(chēng)為線程體。通過(guò)調(diào)用Thread類(lèi)的start()方法來(lái)啟動(dòng)一個(gè)線程。
? ? ? ?(1)Thread類(lèi)
? ? ? ?API中定義的Thread類(lèi):
? ? ? ?線程是程序中的執(zhí)行線程。Java虛擬機(jī)允許應(yīng)用程序并發(fā)地運(yùn)行多個(gè)執(zhí)行線程。 每個(gè)線程都有一個(gè)優(yōu)先級(jí),高優(yōu)
先級(jí)線程的執(zhí)行優(yōu)先于低優(yōu)先級(jí)線程。每個(gè)線程都可以或不可以標(biāo)記為一個(gè)守護(hù)程序。當(dāng)某個(gè)線程中運(yùn)行的代碼創(chuàng)建
一個(gè)新 Thread 對(duì)象時(shí),該新線程的初始優(yōu)先級(jí)被設(shè)定為創(chuàng)建線程的優(yōu)先級(jí),并且當(dāng)且僅當(dāng)創(chuàng)建線程是守護(hù)線程時(shí),
新線程才是守護(hù)程序。?
? ? ? ?當(dāng)Java虛擬機(jī)啟動(dòng)時(shí),通常都會(huì)有單個(gè)非守護(hù)線程(它通常會(huì)調(diào)用某個(gè)指定類(lèi)的 main()方法。Java虛擬機(jī)會(huì)繼續(xù)
執(zhí)行線程,直到下列任一情況出現(xiàn)時(shí)為止:?
? ? ? ? 1)調(diào)用了Runtime類(lèi)的exit()方法,并且安全管理器允許退出操作發(fā)生。?
? ? ? ? 2)非守護(hù)線程的所有線程都已停止運(yùn)行,無(wú)論是通過(guò)從對(duì)run()方法的調(diào)用中返回,還是通過(guò)拋出一個(gè)傳播到run()
方法之外的異常。?
? ? ? ?創(chuàng)建新執(zhí)行線程有兩種方法。一種方法是將類(lèi)聲明為T(mén)hread類(lèi)的子類(lèi)。該子類(lèi)應(yīng)重寫(xiě)Thread類(lèi)的run()方法。接
下來(lái)可以分配并啟動(dòng)該子類(lèi)的實(shí)例。例如,計(jì)算大于某一規(guī)定值的質(zhì)數(shù)的線程可以寫(xiě)成:
[java]?view plaincopy print?
? ? ? ??然后,下列代碼會(huì)創(chuàng)建并啟動(dòng)一個(gè)線程:?
[java]?view plaincopy print?
? ? ? ? 創(chuàng)建線程的另一種方法是聲明實(shí)Runnable接口的類(lèi)。該類(lèi)然后實(shí)現(xiàn)run()方法。然后可以分配該類(lèi)的實(shí)例,在創(chuàng)
建Thread類(lèi)時(shí)作為一個(gè)參數(shù)來(lái)傳遞并啟動(dòng)。采用這種風(fēng)格的同一個(gè)例子如下所示:?
[java]?view plaincopy print?
? ? ? ? 然后,下列代碼會(huì)創(chuàng)建并啟動(dòng)一個(gè)線程:?
[java]?view plaincopy print?
? ? ? ?每個(gè)線程都有一個(gè)標(biāo)識(shí)名,多個(gè)線程可以同名。如果線程創(chuàng)建時(shí)沒(méi)有指定標(biāo)識(shí)名,就會(huì)為其生成一個(gè)新名稱(chēng)。?
? ? ? ?Thread類(lèi)中定義關(guān)于線程優(yōu)先級(jí)的字段:
? ? ? ?Thread類(lèi)中定義的構(gòu)造方法:
? ? ? ?Thread類(lèi)中定義的方法:
? ? ? ?(2)Runnable接口
? ? ? ?API中描述的Runnable接口:
? ? ? ?Runnable接口應(yīng)該由那些打算通過(guò)某一線程執(zhí)行其實(shí)例的類(lèi)來(lái)實(shí)現(xiàn)。類(lèi)必須定義一個(gè)稱(chēng)為run()的無(wú)參數(shù)方法。
?設(shè)計(jì)Runnable接口的目的是為希望在活動(dòng)時(shí)執(zhí)行代碼的對(duì)象提供一個(gè)公共協(xié)議。例如,Thread類(lèi)實(shí)現(xiàn)了Runnable接
口。激活的意思是說(shuō)某個(gè)線程已啟動(dòng)并且尚未停止。?
? ? ? ?此外,Runnable接口為非Thread子類(lèi)的類(lèi)提供了一種激活方式。通過(guò)實(shí)例化某個(gè) Thread類(lèi)實(shí)例并將自身作為運(yùn)
行目標(biāo),就可以運(yùn)行實(shí)現(xiàn)Runnable接口的類(lèi)而無(wú)需創(chuàng)建Thread類(lèi)的子類(lèi)。大多數(shù)情況下,如果只想重寫(xiě)run()方法,
而不重寫(xiě)其他Thread類(lèi)方法,那么應(yīng)使用Runnable接口。這很重要,因?yàn)槌浅绦騿T打算修改或增強(qiáng)類(lèi)的基本行
為,否則不應(yīng)為該類(lèi)創(chuàng)建子類(lèi)。
? ? ? ?Runnable接口中只定義了一個(gè)方法:
?
? ? ? ?(3)線程的創(chuàng)建與啟動(dòng)
? ? ? ?Java中可以有兩種方式創(chuàng)建新的線程。
? ? ? ?第一種:定義線程類(lèi)實(shí)現(xiàn)Runnable接口
? ? ? ?Thread myThread=new Thread(target) ?//target為Runnable接口類(lèi)型。
? ? ? ?Runnable接口中只有一個(gè)方法:
? ? ? ?public void run();//定義線程運(yùn)行體。
? ? ? ?使用Runnable接口可以為多個(gè)線程提供共享的數(shù)據(jù)。
? ? ? ?在實(shí)現(xiàn)Runnable接口的類(lèi)的run()方法中可以使用Thread的靜態(tài)方法:
? ? ? ?public static Thread correntThread() ?獲取當(dāng)前線程的引用
? ? ? ?第二種:定義線程類(lèi)繼承Thread類(lèi)
? ? ? ?定義一個(gè)Thread類(lèi)的子類(lèi)并重寫(xiě)其run()方法如:
? ? ? ?class MyThread extends Thread{
? ? ? ? ? ? ? public void run(){...}
? ? ? ? }
? ? ? ? 然后生成該類(lèi)的對(duì)象:
? ? ? ? MyThread myThread = new Mythread(...)
? ? ? ? 實(shí)例:
? ? ? ? TestThread1.java源代碼:
? ? ? ? 方法調(diào)用的順序執(zhí)行,也就是先執(zhí)行Runnable1線程,再執(zhí)行主線程。
[java]?view plaincopy print?
? ? ? ? 線程啟動(dòng)后的交替執(zhí)行,其中最重要的是Thread類(lèi)的start()方法,即Runnable1線程和主線程交替執(zhí)行。
[java]?view plaincopy print?
? ? ? ? 運(yùn)行結(jié)果:
? ? ? ? 使用繼承Thread類(lèi)的修改后的代碼:
[java]?view plaincopy print?
? ? ? ? 運(yùn)行結(jié)果:
? ? ? ?推薦使用實(shí)現(xiàn)Runnable接口的線程類(lèi)來(lái)進(jìn)行多線程的創(chuàng)建與啟動(dòng),比較靈活。
? ? ? ?關(guān)于兩種方法創(chuàng)建線程的不同
? ? ? ?第一:創(chuàng)建線程只有繼承Thread類(lèi)和實(shí)現(xiàn)Runnable接口兩種方式(Thread也是實(shí)現(xiàn)了Runnable接口);
? ? ? ?第二:若以繼承Thread類(lèi)方式創(chuàng)建線程則這個(gè)類(lèi)的實(shí)例就可以重寫(xiě)Thread類(lèi)的幾十個(gè)方法,注意是好幾十個(gè)方
法;
? ? ? ?第三:若以實(shí)現(xiàn)Runnable接口的方式創(chuàng)建線程則僅僅只有一個(gè)run()方法可供重寫(xiě)(注意是只有一個(gè));
? ? ? ?實(shí)現(xiàn)Runnable接口創(chuàng)建的線程最終還是要通過(guò)將自身實(shí)例作為參數(shù)傳遞給Thread類(lèi)然后執(zhí)行,當(dāng)你要為一個(gè)沒(méi)
有繼承Thread類(lèi)的類(lèi)創(chuàng)建線程,而且只想讓這個(gè)類(lèi)的實(shí)例調(diào)用run()方法執(zhí)行任務(wù),這時(shí)候Runnable接口就相當(dāng)于為
你的目標(biāo)類(lèi)提供了一個(gè)激活方式,設(shè)計(jì)該接口的目的是為了那些希望在激活時(shí)執(zhí)行代碼的對(duì)象提供一個(gè)公共協(xié)議,激
活的意思是說(shuō)某個(gè)線程已啟動(dòng)并且尚未停止。?
? ? ? ?這兩種創(chuàng)建線程的方法本身沒(méi)有什么不同,一個(gè)是實(shí)現(xiàn)Runnable接口,一個(gè)是繼承Thread類(lèi)。而使用實(shí)現(xiàn)
Runnable接口這種方法:1.可以避免Java的單繼承的特性帶來(lái)的局限性;2.適合多個(gè)相同程序的代碼去處理同一個(gè)資
源的情況,把線程同程序的代碼及數(shù)據(jù)有效分離,較好地體現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)思想。開(kāi)發(fā)中大多情況下都使用實(shí)現(xiàn)
Runnable接口這種方法創(chuàng)建線程。
from:?http://blog.csdn.net/erlian1992/article/details/51706914
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的JavaSE入门学习50:多线程编程(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java核心技术点之动态代理
- 下一篇: JavaSE入门学习51:多线程编程(二