java多線程編程集合_第1頁(yè)
java多線程編程集合_第2頁(yè)
java多線程編程集合_第3頁(yè)
java多線程編程集合_第4頁(yè)
java多線程編程集合_第5頁(yè)
已閱讀5頁(yè),還剩90頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、瘋狂大白菜JAVA 多線程編程集合作者:熔巖原文出處:收集制作:CrazyCabbage目錄Java 線程:概念與原理2Java 線程:創(chuàng)建與啟動(dòng)3Java 線程:線程棧模型與線程的變量9Java 線程:線程狀態(tài)的轉(zhuǎn)換10Java 線程:線程的同步與鎖20Java 線程:線程的交互32Java 線程:線程的調(diào)度-休眠36Java 線程:線程的調(diào)度-優(yōu)先級(jí)38Java 線程:線程的調(diào)度-讓步40Java 線程:線程的調(diào)度-合并41Java 線程:線程的調(diào)度-守護(hù)線程43Java 線程:線程的同步-同步.45Java 線程:線程的同步-同步塊49Java 線程:并發(fā)協(xié)作-生產(chǎn)者消費(fèi)者模型51Jav

2、a 線程:并發(fā)協(xié)作-死鎖56Java 線程:volatile 關(guān)鍵字58Java 線程:新特征-線.59ThreadPoolExecutor64Java 線程:新特征-有返回值的線程65Java 線程:新特征-鎖(上)66Java 線程:新特征-鎖(下)70Java 線程:新特號(hào)量73Java 線程:新特征-阻塞隊(duì)列76Java 線程:新特征-阻塞棧77Java 線程:新特征-條件變量79Java 線程:新特征- Java 線程:新特征-量89器931Crazy Cabbage瘋狂大白菜Java 線程:大總結(jié)95Java 線程:概念與原理一、操作系統(tǒng)中線程和進(jìn)程的概念現(xiàn)在的操作系統(tǒng)是多任務(wù)操作

3、系統(tǒng)。多線實(shí)現(xiàn)多任務(wù)的式。進(jìn)指一個(gè)內(nèi)存中運(yùn)行的應(yīng)用程序,每個(gè)進(jìn)有的一塊內(nèi)存空間,一個(gè)進(jìn)可以啟動(dòng)多個(gè)線程。比如在Windows 系統(tǒng)中,一個(gè)運(yùn)行的 exe 就是一個(gè)進(jìn)程。線指進(jìn)的一個(gè)執(zhí)行流程,一個(gè)進(jìn)可以運(yùn)行多個(gè)線程。比如 java.exe進(jìn)可以運(yùn)行很多線程。線程總是屬于某個(gè)進(jìn)程,進(jìn)的多個(gè)線程共享進(jìn)程的內(nèi)存?!巴瑫r(shí)”執(zhí)行是人的感覺(jué),程之間實(shí)際上輪換執(zhí)行。二、Java 中的線程在 Java 中,“線程”指兩件不同的事情:1、java.lang.Thread 類(lèi)的一個(gè)實(shí)例;2、線程的執(zhí)行。使用 java.lang.Thread 類(lèi)或者 java.lang.Runnable 接口編寫(xiě)代碼來(lái)定義、實(shí)例化和

4、啟動(dòng)新線程。一個(gè) Thread 類(lèi)實(shí)例只是一個(gè)對(duì)象,像 Java 中的任何其他對(duì)象一樣,具有變量和方法,生死于堆上。2Crazy Cabbage瘋狂大白菜Java 中,每個(gè)線有一個(gè)調(diào)用棧,即使不在創(chuàng)建任何新的線程,線在運(yùn)行著。一個(gè) Java 應(yīng)用總是從 main()開(kāi)始運(yùn)行,mian()運(yùn)行在一個(gè)線程內(nèi),它被稱(chēng)為主線程。一旦創(chuàng)建一個(gè)新的線程,就產(chǎn)生一個(gè)新的調(diào)用棧。線程總體分兩類(lèi):用戶線守候線程。當(dāng)所有用戶線程執(zhí)行完畢的時(shí)候,JVM 自動(dòng)關(guān)閉。但是守候線程卻不于 JVM,守候線程一般是由操作系統(tǒng)或者用戶創(chuàng)建的。Java 線程:創(chuàng)建與啟動(dòng)一、定義線程1、擴(kuò)展 java.lang.Thread 類(lèi)。

5、此類(lèi)中有個(gè) run(),應(yīng)該注意其用法:如果該線使用的 Runnable 運(yùn)行對(duì)象構(gòu)造的,則調(diào)用該Runnable對(duì)象的 run;否則,該不執(zhí)行任何操作并返回。Thread 的子類(lèi)應(yīng)該重寫(xiě)該。3CrazyCabbagepublic void run()瘋狂大白菜2、實(shí)現(xiàn) java.lang.Runnable 接口。void run()使用實(shí)現(xiàn)接口 Runnable 的對(duì)象創(chuàng)建一個(gè)線,啟動(dòng)該線導(dǎo)致在獨(dú)調(diào)用對(duì)象的 run立執(zhí)行的線。run 的常規(guī)協(xié)定是,它可能執(zhí)行任何所需的操作。二、實(shí)例化線程1、如果是擴(kuò)展 java.lang.Thread 類(lèi)的線程,則直接 new 即可。2、如果是實(shí)現(xiàn)了 jav

6、a.lang.Runnable 接口的類(lèi),則用 Thread 的構(gòu)造:Thread(Runnable target)Thread(Runnable target, String name)Thread(ThreadGroupgroup,Runnabletarget)Thread(ThreadGroupgroup,Runnabletarget, String name)Thread(ThreadGroupgroup,Runnabletarget, String name, long stackSize)三、啟動(dòng)線程程的 Thread 對(duì)象上調(diào)用 start(),而不是 run()或者別的。4Cr

7、azyCabbage瘋狂大白菜在調(diào)用 start()之前:線程處于新?tīng)顟B(tài)中,新?tīng)顟B(tài)指有一個(gè) Thread 對(duì)象,但還沒(méi)有一個(gè)真正的線程。在調(diào)用 start()之后:發(fā)生了一系列復(fù)雜的事情啟動(dòng)新的執(zhí)行線程(具有新的調(diào)用棧);該線程從新?tīng)顟B(tài)轉(zhuǎn)移到可運(yùn)行狀態(tài);當(dāng)該線程獲得機(jī)會(huì)執(zhí)行時(shí),其目標(biāo) run()將運(yùn)行。注意:對(duì) Java 來(lái)說(shuō),run()沒(méi)有任何特別之處。像 main()一樣,它只是新線程知道調(diào)用的名稱(chēng)(和簽名)。因此,在 Runnable 上或者 Thread 上調(diào)用 run是合法的。但并不啟動(dòng)新的線程。四、例子1、實(shí)現(xiàn) Runnable 接口的多線程例子5CrazyCabbage/* 實(shí)現(xiàn)

8、Runnable 接口的類(lèi)* author leizhimin 2008-9-13 18:12:10*/public class DoSomething implements Runnable private String name;public DoSomething(String name) = name;瘋狂大白菜執(zhí)行結(jié)果:6CrazyCabbage李四: 0阿三: 0李四: 1阿三: 1李四: 2李四: 3阿三: 2李四: 4阿三: 3阿三: 4Process finished with exit code 0/* 測(cè)試Runnable 類(lèi)實(shí)現(xiàn)的多線程程序* aut

9、hor leizhimin 2008-9-13 18:15:02*/public class TestRunnable public static void main(String args) DoSomething ds1 = new DoSomething("阿三"); DoSomething ds2 = new DoSomething("李四");Thread t1 = new Thread(ds1); Thread t2 = new Thread(ds2);t1.start();t2.start();public void run() for (

10、int i = 0; i < 5; i+) for (long k = 0; k < 100000000; k+) ; System.out.println(name + ": " + i);瘋狂大白菜2、擴(kuò)展 Thread 類(lèi)實(shí)現(xiàn)的多線程例子執(zhí)行結(jié)果:7CrazyCabbage阿三 :0李四 :0阿三 :1李四 :1阿三 :2李四 :2阿三 :3阿三 :4李四 :3李四 :4Process finished with exit code 0/* 測(cè)試擴(kuò)展Thread 類(lèi)實(shí)現(xiàn)的多線程程序* author leizhimin 2008-9-13 18:22:13*

11、/public class TestThread extends Thread public TestThread(String name) super(name);public void run() for(int i = 0;i<5;i+)for(long k= 0; k <100000000;k+); System.out.println(this.getName()+" :"+i);public static void main(String args) Thread t1 = new TestThread("阿三"); Thread

12、 t2 = new TestThread("李四"); t1.start();t2.start();瘋狂大白菜對(duì)于上面的多線程程序代碼來(lái)說(shuō),輸出的結(jié)果是不確定的。其中的一條語(yǔ)句for(long k= 0; k <100000000;k+);是用來(lái)模擬一個(gè)非常耗時(shí)的操作的。五、一些常見(jiàn)1、線程的名字,一個(gè)運(yùn)行中的線程總是有名字的,名字有兩個(gè)來(lái)源,一個(gè)是虛擬機(jī)給的名字,一個(gè)是你的定的名字。在沒(méi)有指定線程名字的情況下,虛擬機(jī)總會(huì)為線程指定名字,并且主線程的名字總是 mian,非主線程的名字不確定。2、線可以設(shè)置名字,也可以獲取線程的名字,連主線不例外。3、獲取當(dāng)前線程的對(duì)象

13、的是:Thread.currentThread();4、在上面的代碼中,只能保證:每個(gè)線將啟動(dòng),每個(gè)線將運(yùn)行直到完成。一系列線程以某種順序啟動(dòng)并不意味著將按該順序執(zhí)行。對(duì)于任何一組啟動(dòng)的線程來(lái)說(shuō),調(diào)度程序不能保證其執(zhí)行次序,持續(xù)時(shí)間也無(wú)法保證。5、當(dāng)線程目標(biāo) run()結(jié)束時(shí)該線程完成。6、一旦線程啟動(dòng),它就永遠(yuǎn)不能再重新啟動(dòng)。只有一個(gè)新的線程可以被啟動(dòng),并且只能一次。一個(gè)可運(yùn)行的線程或死線程可以被重新啟動(dòng)。7、線程的調(diào)度是 JVM 的一部分,在一個(gè) CPU 的上上,實(shí)際上一次只能運(yùn)行一個(gè)線程。一次只有一個(gè)線程棧執(zhí)行。JVM 線程調(diào)度程序決定實(shí)際運(yùn)行哪個(gè)處于可運(yùn)行狀態(tài)的線程。眾多可運(yùn)行線的某一

14、個(gè)會(huì)被選中做為當(dāng)前線程??蛇\(yùn)行線程被選擇運(yùn)行的順序是沒(méi)有保障的。8Crazy Cabbage瘋狂大白菜8、盡管通常采用隊(duì)列形式,但這是沒(méi)有保障的。隊(duì)列形式是指當(dāng)一個(gè)線程完成“一輪”時(shí),它移到可運(yùn)行隊(duì)列的待,直到它最終排隊(duì)到該隊(duì)列的前端為止,它才能被再次選中。事實(shí)上,我們把它稱(chēng)為可運(yùn)行池而不是一個(gè)可運(yùn)行隊(duì)列,目的是幫助認(rèn)識(shí)線程并不都是以某種有保障的順序排列唱呢個(gè)一個(gè)隊(duì)列的事實(shí)。9、盡管我們沒(méi)有無(wú)法線程調(diào)度程序,但可以通過(guò)別的方式來(lái)影響線程調(diào)度的方式。Java 線程:線程棧模型與線程的變量SCJP5 學(xué)習(xí)筆記要理解線程調(diào)度的原理,以及線程執(zhí)行過(guò)程,必須理解線程棧模型。線程棧是指某時(shí)刻時(shí)內(nèi)存中線程調(diào)

15、度的棧信息,當(dāng)前調(diào)用的總是位于棧頂。線程棧的內(nèi)容是隨著程序的運(yùn)行動(dòng)態(tài)變化的,因此研究線程棧必須選擇一個(gè)運(yùn)行的時(shí)刻(實(shí)際上指代碼運(yùn)行到什么地方)。下面通過(guò)一個(gè)示例性的代碼說(shuō)明線程(調(diào)用)棧的變化過(guò)程。這幅圖描述在代碼執(zhí)行到兩個(gè)不同時(shí)刻 1、2 時(shí)候,虛擬機(jī)線程調(diào)用棧示意圖。當(dāng)程序執(zhí)行到 t.start();時(shí)候,出一個(gè)分支(增加了一個(gè)調(diào)用棧 B),這樣,棧 A、棧 B 并行執(zhí)行。9Crazy Cabbage瘋狂大白菜從這里就可以看出調(diào)用和線程啟動(dòng)的區(qū)別了。Java 線程:線程狀態(tài)的轉(zhuǎn)換一、線程狀態(tài)線程的狀態(tài)轉(zhuǎn)換是線程的基礎(chǔ)。線程狀態(tài)總的可分為五大狀態(tài):分別是生、死、可運(yùn)行、運(yùn)行、等待/阻塞。用一

16、個(gè)圖來(lái)描述如下:1、新?tīng)顟B(tài):線程對(duì)象已經(jīng)創(chuàng)建,還沒(méi)有在其上調(diào)用 start()。2、可運(yùn)行狀態(tài):當(dāng)線程有資格運(yùn)行,但調(diào)度程序還沒(méi)有把它選定為運(yùn)行線線程所處的狀態(tài)。當(dāng) start()調(diào)用時(shí),線程首先進(jìn)入可運(yùn)行狀態(tài)。程運(yùn)行之后或者從阻塞、等待或睡眠狀態(tài)回來(lái)后,也返回到可運(yùn)行狀態(tài)。3、運(yùn)行狀態(tài):線程調(diào)度程序從可運(yùn)行選擇一個(gè)線程作為當(dāng)前線線處的狀態(tài)。這也是線程進(jìn)入運(yùn)行狀態(tài)的唯一式。4、等待/阻塞/睡眠狀態(tài):這是線程有資格運(yùn)行時(shí)它所處的狀態(tài)。實(shí)際上這個(gè)三狀態(tài)組合為一種,其共同點(diǎn)是:線程仍舊是活的,但是當(dāng)前沒(méi)有條件運(yùn)行。換句話說(shuō),它是可運(yùn)行的,但是如果某件出現(xiàn),他可能返回到可運(yùn)行狀態(tài)。10Crazy Ca

17、bbage瘋狂大白菜5、態(tài):當(dāng)線程的 run()完成認(rèn)為它死去。這個(gè)線程對(duì)象也許是活的,但是,它已經(jīng)不是一個(gè)單獨(dú)執(zhí)行的線程。線程一旦,就不能復(fù)生。 如果在一個(gè)死去的線程上調(diào)用 start(),會(huì)拋出 java.lang.IllegalThreadStateException異常。二、線程執(zhí)行對(duì)于線程的,考慮一下三個(gè)方面,不考慮 IO 阻塞的情況:睡眠;等待;因?yàn)樾枰粋€(gè)對(duì)象的鎖定而被阻塞。1、睡眠Thread.sleep(long millis)和 Thread.sleep(long millis, int nanos)靜態(tài)強(qiáng)制當(dāng)前正在執(zhí)行的線程休眠(暫停執(zhí)行),以“減慢線程”。當(dāng)線程睡眠時(shí),

18、它入睡在某個(gè)地方,在蘇醒之前返回到可運(yùn)行狀態(tài)。當(dāng)睡眠時(shí)間到期,則返回到可運(yùn)行狀態(tài)。線程睡眠的:線程執(zhí)行太快,或者需要強(qiáng)制進(jìn)入下一輪,因?yàn)?Java 規(guī)范不保證合理的輪換。睡眠的實(shí)現(xiàn):調(diào)用靜態(tài)。11Crazy Cabbage瘋狂大白菜try Thread.sleep(123); catch (InterruptedException e) e.printStackTrace();睡眠的位置:為了讓其他線程有機(jī)會(huì)執(zhí)行,可以將 Thread.sleep()的調(diào)用放線程run()之內(nèi)。這樣才能保證該線程執(zhí)行過(guò)會(huì)睡眠。例如,在前面的例子中,將一個(gè)耗時(shí)的操作改為睡眠,以減慢線程的執(zhí)行。可以這么寫(xiě):publ

19、ic void run() for(int i = 0;i<5;i+)/很耗時(shí)的操作,用來(lái)減慢線程的執(zhí)行/for(long k= 0; k <100000000;k+);try Thread.sleep(3); catch (InterruptedException e) e.printStackTrace();.System.out.println(this.getName()+":"+i);12Crazy Cabbage瘋狂大白菜運(yùn)行結(jié)果:這樣,線每次執(zhí)行過(guò),總會(huì)睡眠 3 毫秒,睡眠了,其他的線程就有機(jī)會(huì)執(zhí)行了。注意:1、線程睡眠是幫助所有線程獲得運(yùn)行機(jī)會(huì)的

20、最好。2、線程睡眠到期自動(dòng)蘇醒,并返回到可運(yùn)行狀態(tài),不是運(yùn)行狀態(tài)。sleep()中指定的時(shí)間是線程運(yùn)行的最短時(shí)間。因此,sleep()不能保證該線程睡眠到期后就開(kāi)始執(zhí)行。3、sleep()是靜態(tài),只能當(dāng)前正在運(yùn)行的線程。下面給個(gè)例子:13Crazy Cabbage阿三 :0李四 :0阿三 :1阿三 :2阿三 :3李四 :1李四 :2阿三 :4李四 :3李四 :4Process finished with exit code 0瘋狂大白菜14CrazyCabbage00 線程睡眠 1 毫秒!1 線程睡眠 1 毫秒!2 線程睡眠 1 毫秒!3 線程睡眠 1 毫秒!4 線程睡眠 1 毫秒!5 線程睡

21、眠 1 毫秒!6 線程睡眠 1 毫秒!7 線程睡眠 1 毫秒!8 線程睡眠 1 毫秒!9 線程睡眠 1 毫秒!1010 線程睡眠 1 毫秒!11 線程睡眠 1 毫秒!12 線程睡眠 1 毫秒!13 線程睡眠 1 毫秒!/* 一個(gè)計(jì)數(shù)器,計(jì)數(shù)到 100,在每個(gè)數(shù)字之間暫停 1 秒,每隔 10 個(gè)數(shù)字輸出一個(gè)字符串* author leizhimin 2008-9-14 9:53:49*/public class MyThread extends Thread public void run() for (int i = 0; i < 100; i+) if (i) % 10 = 0) Sy

22、stem.out.println("-" + i);System.out.print(i); try Thread.sleep(1);System.out.print("線程睡眠 1 毫秒!n"); catch (InterruptedException e) e.printStackTrace();public static void main(String args) new MyThread().start();瘋狂大白菜15CrazyCabbage14 線程睡眠 1 毫秒!15 線程睡眠 1 毫秒!16 線程睡眠 1 毫秒!17 線程睡眠 1 毫

23、秒!18 線程睡眠 1 毫秒!19 線程睡眠 1 毫秒!2020 線程睡眠 1 毫秒!21 線程睡眠 1 毫秒!22 線程睡眠 1 毫秒!23 線程睡眠 1 毫秒!24 線程睡眠 1 毫秒!25 線程睡眠 1 毫秒!26 線程睡眠 1 毫秒!27 線程睡眠 1 毫秒!28 線程睡眠 1 毫秒!29 線程睡眠 1 毫秒!3030 線程睡眠 1 毫秒!31 線程睡眠 1 毫秒!32 線程睡眠 1 毫秒!33 線程睡眠 1 毫秒!34 線程睡眠 1 毫秒!35 線程睡眠 1 毫秒!36 線程睡眠 1 毫秒!37 線程睡眠 1 毫秒!38 線程睡眠 1 毫秒!39 線程睡眠 1 毫秒!4040 線程睡

24、眠 1 毫秒!41 線程睡眠 1 毫秒!42 線程睡眠 1 毫秒!43 線程睡眠 1 毫秒!44 線程睡眠 1 毫秒!45 線程睡眠 1 毫秒!46 線程睡眠 1 毫秒!47 線程睡眠 1 毫秒!48 線程睡眠 1 毫秒!49 線程睡眠 1 毫秒!5050 線程睡眠 1 毫秒!51 線程睡眠 1 毫秒!52 線程睡眠 1 毫秒!53 線程睡眠 1 毫秒!瘋狂大白菜16CrazyCabbage54 線程睡眠 1 毫秒!55 線程睡眠 1 毫秒!56 線程睡眠 1 毫秒!57 線程睡眠 1 毫秒!58 線程睡眠 1 毫秒!59 線程睡眠 1 毫秒!6060 線程睡眠 1 毫秒!61 線程睡眠 1

25、毫秒!62 線程睡眠 1 毫秒!63 線程睡眠 1 毫秒!64 線程睡眠 1 毫秒!65 線程睡眠 1 毫秒!66 線程睡眠 1 毫秒!67 線程睡眠 1 毫秒!68 線程睡眠 1 毫秒!69 線程睡眠 1 毫秒!7070 線程睡眠 1 毫秒!71 線程睡眠 1 毫秒!72 線程睡眠 1 毫秒!73 線程睡眠 1 毫秒!74 線程睡眠 1 毫秒!75 線程睡眠 1 毫秒!76 線程睡眠 1 毫秒!77 線程睡眠 1 毫秒!78 線程睡眠 1 毫秒!79 線程睡眠 1 毫秒!8080 線程睡眠 1 毫秒!81 線程睡眠 1 毫秒!82 線程睡眠 1 毫秒!83 線程睡眠 1 毫秒!84 線程睡眠

26、 1 毫秒!85 線程睡眠 1 毫秒!86 線程睡眠 1 毫秒!87 線程睡眠 1 毫秒!88 線程睡眠 1 毫秒!89 線程睡眠 1 毫秒!9090 線程睡眠 1 毫秒!91 線程睡眠 1 毫秒!92 線程睡眠 1 毫秒!93 線程睡眠 1 毫秒!瘋狂大白菜2、線程的優(yōu)先級(jí)和線程讓步 yield()線程的讓步是通過(guò) Thread.yield()來(lái)實(shí)現(xiàn)的。yield()的作用是:暫停當(dāng)前正在執(zhí)行的線程對(duì)象,并執(zhí)行其他線程。要理解 yield(),必須了解線程的優(yōu)先級(jí)的概念。線程總是優(yōu)先級(jí),優(yōu)先級(jí)范圍在 110 之間。JVM 線程調(diào)度程序是基于優(yōu)先級(jí)的搶先調(diào)度機(jī)制。在大多數(shù)情況下,當(dāng)前運(yùn)行的線程

27、優(yōu)先級(jí)將大于或等于線中任何線程的優(yōu)先級(jí)。但這僅僅是大多數(shù)情況。注意:當(dāng)設(shè)計(jì)多線程應(yīng)用程序的時(shí)候,一定不要依賴(lài)于線程的優(yōu)先級(jí)。因?yàn)榫€程調(diào)度優(yōu)先級(jí)操作是沒(méi)有保障的,只能把線程優(yōu)先級(jí)作用作為一種提高程序效率的,但是要保證程序不依賴(lài)這種操作。當(dāng)線中線具有相同的優(yōu)先級(jí),調(diào)度程序的 JVM 實(shí)現(xiàn)選擇它喜歡的線程。這時(shí)候調(diào)度程序的操作有兩種可能:一是選擇一個(gè)線程運(yùn)行,直到它阻塞或者運(yùn)行完成為止。二是時(shí)間分片,為池內(nèi)的每個(gè)線程提供均等的運(yùn)行機(jī)會(huì)。17Crazy Cabbage94 線程睡眠 1 毫秒!95 線程睡眠 1 毫秒!96 線程睡眠 1 毫秒!97 線程睡眠 1 毫秒!98 線程睡眠 1 毫秒!99

28、線程睡眠 1 毫秒!Process finished with exit code 0瘋狂大白菜設(shè)置線程的優(yōu)先級(jí):線程默認(rèn)的優(yōu)先級(jí)是創(chuàng)建它的執(zhí)行線程的優(yōu)先級(jí)??梢酝ㄟ^(guò)setPriority(int newPriority)更改線程的優(yōu)先級(jí)。例如:Thread t = new MyThread();t.setPriority(8);t.start();線程優(yōu)先級(jí)為 110 之間的正整數(shù),JVM 從改變一個(gè)線程的優(yōu)先級(jí)。,110之間的值是沒(méi)有保證的。一些 JVM 可能不能識(shí)別 10 個(gè)不同的值,而將這些優(yōu)先級(jí)進(jìn)行每?jī)蓚€(gè)或多個(gè)合并,變成少于 10 個(gè)的優(yōu)先級(jí),則兩個(gè)或多個(gè)優(yōu)先級(jí)的線程可能被為一個(gè)優(yōu)先

29、級(jí)。線程默認(rèn)優(yōu)先級(jí)是 5,Thread 類(lèi)中有三個(gè)常量,定義線程優(yōu)先級(jí)范圍:staticint MAX_PRIORITY線程可以具有的最高優(yōu)先級(jí)。staticint MIN_PRIORITY線程可以具有的最低優(yōu)先級(jí)。staticint NORM_PRIORITY分配給線程的默認(rèn)優(yōu)先級(jí)。3、Thread.yield()Thread.yield()作用是:暫停當(dāng)前正在執(zhí)行的線程對(duì)象,并執(zhí)行其他線程。18CrazyCabbage瘋狂大白菜yield()應(yīng)該做的是讓當(dāng)前運(yùn)行線程回到可運(yùn)行狀態(tài),以具有相同優(yōu)先級(jí)的其他線程獲得運(yùn)行機(jī)會(huì)。因此,使用 yield()的目的是讓相同優(yōu)先級(jí)的線程之間能適當(dāng)?shù)妮嗈D(zhuǎn)執(zhí)

30、行。但是,實(shí)際中無(wú)法保證yield()達(dá)到讓步目的,因?yàn)樽尣降木€程還有可能被線程調(diào)度程序再次選中。結(jié)論:yield()從未導(dǎo)致線程轉(zhuǎn)到等待/睡眠/阻塞狀態(tài)。在大多數(shù)情況下,yield()將導(dǎo)致線程從運(yùn)行狀態(tài)轉(zhuǎn)到可運(yùn)行狀態(tài),但有可能沒(méi)有效果。4、join()Thread 的非靜態(tài)join()讓一個(gè)線程 B“加入”到另外一個(gè)線程 A 的尾部。在 A執(zhí)行完畢之前,B 不能工作。例如:Thread t = new MyThread();t.start();t.join();另外,join()還有帶超時(shí)限制的重載版本。 例如 t.join(5000);則讓線程等待5000 毫秒,如果超過(guò)這個(gè)時(shí)間,則停止

31、等待,變?yōu)榭蛇\(yùn)行狀態(tài)。線程的加入 join()對(duì)線程棧導(dǎo)致的結(jié)果是線程棧發(fā)生了變化,當(dāng)然這些變化都是瞬時(shí)的。下面給示意圖:小結(jié)19Crazy Cabbage瘋狂大白菜到目前位置,了線程離開(kāi)運(yùn)行狀態(tài)的 3 種:1、調(diào)用 Thread.sleep():使當(dāng)前線程睡眠至少多少毫秒(盡管它可能在指定的時(shí)間之前被中斷)。2、調(diào)用 Thread.yield():不能保障太多事情,盡管通常它會(huì)讓當(dāng)前運(yùn)行線程回到可運(yùn)行性狀態(tài),使得有相同優(yōu)先級(jí)的線程有機(jī)會(huì)執(zhí)行。3、調(diào)用 join():保證當(dāng)前線程停止執(zhí)行,直到該線加入的線程完成為止。,如果它加入的線程沒(méi)有存活,則當(dāng)前線程不需要停止。除了以上三種,還有下面幾種特

32、殊情況可能使線程離開(kāi)運(yùn)行狀態(tài):1、線程的 run()完成。2、在對(duì)象上調(diào)用 wait()(不是程上調(diào)用)。3、線程不能在對(duì)象上獲得鎖定,它正試圖運(yùn)行該對(duì)象的代碼。4、線程調(diào)度程序可以決定將當(dāng)前運(yùn)行狀態(tài)移動(dòng)到可運(yùn)行狀態(tài),以便讓另一個(gè)線程獲得運(yùn)行機(jī)會(huì),而不需要任何理由。Java 線程:線程的同步與鎖一、同步提出20Crazy Cabbage瘋狂大白菜線程的同步是為了防止多個(gè)線程一個(gè)數(shù)據(jù)對(duì)象時(shí),對(duì)數(shù)據(jù)造成的破壞。例如:兩個(gè)線程 ThreadA、ThreadB 都操作同一個(gè)對(duì)象 Foo 對(duì)象,并修改 Foo 對(duì)象上的數(shù)據(jù)。21Crazy Cabbagepublic class MyRunnable i

33、mplements Runnable private Foo foo = new Foo();public static void main(String args) MyRunnable r = new MyRunnable(); Thread ta = new Thread(r, "Thread-A"); Thread tb = new Thread(r, "Thread-B"); ta.start();tb.start();public void run() for (int i = 0; i < 3; i+) this.fix(30);tr

34、y Thread.sleep(1); catch (InterruptedException e) e.printStackTrace();System.out.println(Thread.currentThread().getName() + " : 當(dāng)前foo 對(duì)象的x 值= " + foo.getX();public class Foo private int x = 100;public int getX() return x;public int fix(int y) x = x - y;return x;瘋狂大白菜運(yùn)行結(jié)果:從結(jié)果發(fā)現(xiàn),這樣的輸出值明顯是不合理

35、的。是兩個(gè)線程不加的Foo對(duì)象并修改其數(shù)據(jù)所致。如果要保持結(jié)果的合理性,只需要達(dá)到一個(gè)目的,就是將對(duì) Foo 的加以限制,每次只能有一個(gè)線。這樣就能保證 Foo 對(duì)象中數(shù)據(jù)的合理性了。在具體的 Java 代碼中需要完成一下兩個(gè)操作:把競(jìng)爭(zhēng)的類(lèi) Foo 變量 x 標(biāo)識(shí)為 private;同步哪些修改變量的代碼,使用 synchronized 關(guān)鍵字同步或代碼。二、同步和鎖定22CrazyCabbageThread-A : 當(dāng)前foo 對(duì)象的x 值= 40 Thread-B : 當(dāng)前foo 對(duì)象的x 值= 40 Thread-B : 當(dāng)前foo 對(duì)象的x 值= -20 Thread-A : 當(dāng)前f

36、oo 對(duì)象的x 值= -50 Thread-A : 當(dāng)前foo 對(duì)象的x 值= -80 Thread-B : 當(dāng)前foo 對(duì)象的x 值= -80Process finished with exit code 0public int fix(int y) return foo.fix(y);瘋狂大白菜1、鎖的原理Java 中每個(gè)對(duì)象一個(gè)內(nèi)置鎖當(dāng)程序運(yùn)行到非靜態(tài)的 synchronized 同步上時(shí),自動(dòng)獲得與正在執(zhí)行代碼類(lèi)的當(dāng)前實(shí)例(this 實(shí)例)有。獲得一個(gè)對(duì)象的鎖也稱(chēng)為獲取鎖、鎖定對(duì)象、在對(duì)象上鎖定或在對(duì)象上同步。當(dāng)程序運(yùn)行到 synchronized 同步或代碼塊時(shí)才該對(duì)象鎖才起作用。一

37、個(gè)對(duì)象只有一個(gè)鎖。所以,如果一個(gè)線程獲得該鎖,就沒(méi)有其他線程可以獲得鎖,直到第一個(gè)線程(或返回)鎖。這也意味著任何其他線不能進(jìn)入該對(duì)象上的 synchronized或代碼塊,直到該鎖被。鎖是指持鎖線程了 synchronized 同步或代碼塊。關(guān)于鎖和同步,有一下幾個(gè)要點(diǎn):1)、只能同步,而不能同步變量和類(lèi);2)、每個(gè)對(duì)象只有一個(gè)鎖;當(dāng)提到同步時(shí),應(yīng)該清楚在什么上同步?也就是說(shuō),在哪個(gè)對(duì)象上同步?3)、不必同步類(lèi)中所有的,類(lèi)可以同時(shí)擁有同步和非同步。23Crazy Cabbage瘋狂大白菜4)、如果兩個(gè)線程要執(zhí)行一個(gè)類(lèi)中的 synchronized,并且兩個(gè)線程使用相同的實(shí)例來(lái)調(diào)用,那么一次只

38、能有一個(gè)線程能夠執(zhí)行,另一個(gè)需要等待,直到鎖被。也就是說(shuō):如果一個(gè)線對(duì)象上獲得一個(gè)鎖,就沒(méi)有任何其他線程可以進(jìn)入(該對(duì)象的)類(lèi)中的任何一個(gè)同步。5)、如果線程擁有同步和非同步,則非同步可以被多個(gè)線程而不受鎖的限制。6)、線程睡眠時(shí),它所持的任何鎖都。7)、線程可以獲得多個(gè)鎖。比如,在一個(gè)對(duì)象的同步里面調(diào)用另外一個(gè)對(duì)象的同步,則獲取了兩個(gè)對(duì)象的同步鎖。8)、同步損害并發(fā)性,應(yīng)該盡可能縮小同步范圍。同步不但可以同步整個(gè),還可以同步中一部分代碼塊。9)、在使用同步代碼塊時(shí)候,應(yīng)該指定在哪個(gè)對(duì)象上同步,也就是說(shuō)要獲取哪個(gè)對(duì)象的鎖。例如:public int fix(int y) synchronize

39、d (this) x = x - y;return x;當(dāng)然,同步也可以改寫(xiě)為非同步,但功能完全一樣的,例如:24Crazy Cabbage瘋狂大白菜public synchronized intgetX()return x+;與public int getX() synchronized (this)return x;效果是完全一樣的。三、靜態(tài)同步要同步靜態(tài),需要一個(gè)用于整個(gè)類(lèi)對(duì)象的鎖,這個(gè)對(duì)象是就是這個(gè)類(lèi)(.class)。例如:public static synchronized int setName(String name).name = name;等價(jià)于public static i

40、nt setName(String name)synchronized(.class)25CrazyCabbage瘋狂大白菜.name = name;四、如果線程不能不能獲得鎖會(huì)怎么樣如果線程試圖進(jìn)入同步,而其鎖已經(jīng)被占用,則線該對(duì)象上被阻塞。實(shí)質(zhì)上,線程進(jìn)入該對(duì)象的的一種,必須在哪里等待,直到其鎖被,該線次變?yōu)榭蛇\(yùn)行或運(yùn)行為止。當(dāng)考慮阻塞時(shí),一定要注意哪個(gè)對(duì)象正被用于鎖定:1、調(diào)用同一個(gè)對(duì)象中非靜態(tài)同步的線彼此阻塞。如果是不同對(duì)象,則每個(gè)線程有的對(duì)象的鎖,線程間彼此互不干預(yù)。2、調(diào)用同一個(gè)類(lèi)中的靜態(tài)同步的線彼此阻塞,它們都是鎖定在相同的Class 對(duì)象上。3、靜態(tài)同步和非靜態(tài)同步將永遠(yuǎn)彼此阻

41、塞,因?yàn)殪o態(tài)鎖定在Class 對(duì)象上,非靜態(tài)鎖定在該類(lèi)的對(duì)象上。26CrazyCabbage瘋狂大白菜4、對(duì)于同步代碼塊,要看清楚什么對(duì)象已經(jīng)用于鎖定(synchronized 后面括號(hào)的內(nèi)容)。在同一個(gè)對(duì)象上進(jìn)行同步的線彼此阻塞,在不同對(duì)象上鎖定的線永遠(yuǎn)彼此阻塞。五、何時(shí)需要同步在多個(gè)線程同時(shí)互斥(可交換)數(shù)據(jù)時(shí),應(yīng)該同步以保護(hù)數(shù)據(jù),確保兩個(gè)線程同時(shí)修改更改它。對(duì)于非靜態(tài)字段中可更改的數(shù)據(jù),通常使用非靜態(tài)。對(duì)于靜態(tài)字段中可更改的數(shù)據(jù),通常使用靜態(tài)。如果需要在非靜態(tài)中使用靜態(tài)字段,或者在靜態(tài)字段中調(diào)用非靜態(tài),將變得非常復(fù)雜。已經(jīng)超出 SJCP范圍了。六、線程安全類(lèi)當(dāng)一個(gè)類(lèi)已經(jīng)很好的同步以保護(hù)它

42、的數(shù)據(jù)時(shí),這個(gè)類(lèi)就稱(chēng)為“線程安全的”。即使是線程安全類(lèi),也應(yīng)該特別,因?yàn)椴僮鞯木€間仍然不一定安全。27CrazyCabbage瘋狂大白菜舉個(gè)形象的例子,比如一個(gè)集合是線程安全的,有兩個(gè)線操作同一個(gè)集合對(duì)象,當(dāng)?shù)谝粋€(gè)線程集合非空后,刪除集合中所有元素的時(shí)候。第二個(gè)線來(lái)執(zhí)行與第一個(gè)線程相同的操作,也許在第一個(gè)線程后,第二個(gè)線出集合非空,但是當(dāng)?shù)谝粋€(gè)執(zhí)行清除后,第二個(gè)再執(zhí)行刪除顯然是不對(duì)的,因?yàn)榇藭r(shí)集合已經(jīng)為空了。看個(gè)代碼:28Crazy Cabbagepublic class Test public static void main(String args) final NameList nl =

43、 new NameList(); nl.add("aaa");class NameDropper extends Thread public void run()String name = nl.removeFirst(); System.out.println(name);Thread t1 = new NameDropper(); Thread t2 = new NameDropper();public class NameList private List nameList = Collections.synchronizedList(new LinkedList()

44、;public void add(String name) nameList.add(name);public String removeFirst() if (nameList.size() > 0) return (String) nameList.remove(0); else return null;瘋狂大白菜雖然集合對(duì)象private List nameList = Collections.synchronizedList(new LinkedList();是同步的,但是程序還不是線程安全的。出現(xiàn)這種的是,上例中一個(gè)線程操作列表過(guò)無(wú)法另外一個(gè)線程對(duì)列表的其他操作。解決上面的辦法

45、是,在操作集合對(duì)象的 NameList 上面做一個(gè)同步。改寫(xiě)后的代碼如下:這樣,當(dāng)一個(gè)線程其中一個(gè)同步時(shí),其他線程只有等待。七、線程死鎖29Crazy Cabbagepublic class NameList private List nameList = Collections.synchronizedList(new LinkedList();public synchronized void add(String name) nameList.add(name);public synchronized String removeFirst() if (nameList.size() >

46、; 0) return (String) nameList.remove(0); else return null;t1.start();t2.start();瘋狂大白菜死鎖對(duì) Java說(shuō),是很復(fù)雜的,也很難發(fā)現(xiàn)。當(dāng)兩個(gè)線程被阻塞,每個(gè)線等待另一個(gè)線就發(fā)生死鎖。還是看一個(gè)比較直觀的死鎖例子:假設(shè) read()由一個(gè)線程啟動(dòng),write()由另外一個(gè)線程啟動(dòng)。讀線擁有 resourceA 鎖,寫(xiě)線擁有 resourceB 鎖,兩者都堅(jiān)持等待的話就出現(xiàn)死鎖。30Crazy Cabbagepublic class DeadlockRisk private static class Resource

47、public int value;private Resource resourceA = new Resource(); private Resource resourceB = new Resource();public int read() synchronized (resourceA) synchronized (resourceB) return resourceB.value + resourceA.value;public void write(int a, int b) synchronized (resourceB) synchronized (resourceA) res

48、ourceA.value = a; resourceB.value = b;瘋狂大白菜實(shí)際上,上面這個(gè)例子發(fā)生死鎖的概率很小。因?yàn)樵诖a內(nèi)的某個(gè)點(diǎn),CPU 必須從讀線程切換到寫(xiě)線以,死鎖基本上不能發(fā)生。但是,無(wú)論代碼中發(fā)生死鎖的概率有多小,一旦發(fā)生死鎖,程序就死掉。有一些設(shè)計(jì)能幫助避免死鎖,始終按照預(yù)定義的順序獲取鎖這一策略。已經(jīng)超出SCJP 的范圍。八、線程同步小結(jié)1、線程同步的目的是為了保護(hù)多個(gè)線程反問(wèn)一個(gè)時(shí)對(duì)的破壞。2、線程同步是通過(guò)鎖來(lái)實(shí)現(xiàn),每個(gè)對(duì)象切僅有一個(gè)鎖,這個(gè)鎖與一個(gè)特定的對(duì)象關(guān)聯(lián),線程一旦獲取了對(duì)象鎖,其他該對(duì)象的線程就無(wú)法再該對(duì)象的其他同步。3、對(duì)于靜態(tài)同步,鎖是這個(gè)類(lèi)的,

49、鎖對(duì)象是該類(lèi)的 Class 對(duì)象。靜態(tài)和非靜態(tài)的鎖互不干預(yù)。一個(gè)線程獲得鎖,當(dāng)在一個(gè)同步中另外對(duì)象上的同步時(shí),會(huì)獲取這兩個(gè)對(duì)象鎖。4、對(duì)于同步,要時(shí)刻清醒在哪個(gè)對(duì)象上同步,這是關(guān)鍵。5、編寫(xiě)線程安全的類(lèi),需要時(shí)刻注意對(duì)多個(gè)線程競(jìng)爭(zhēng)的邏輯和安全做出正確的,對(duì)“”操作做出分析,操作期間別的線程無(wú)法競(jìng)爭(zhēng)。6、當(dāng)多個(gè)線程等待一個(gè)對(duì)象鎖時(shí),沒(méi)有獲取到鎖的線發(fā)生阻塞。31Crazy Cabbage瘋狂大白菜7、死鎖是線程間相互等待鎖鎖造成的,在實(shí)際中發(fā)生的概率非常的小。真讓你寫(xiě)個(gè)死鎖程序,不一定好使,呵呵。但是,一旦程序發(fā)生死鎖,程序?qū)⑺赖?。Java 線程:線程的交互SCJP5 學(xué)習(xí)筆記線程交互是比較復(fù)雜

50、的,SCJP 要求不很基礎(chǔ):給定一個(gè)場(chǎng)景,編寫(xiě)代碼來(lái)恰當(dāng)使用等待、通知和通知所有線程。一、線程交互的基礎(chǔ)知識(shí)SCJP 所要求的線程交互知識(shí)點(diǎn)需要從java.lang.Object 的類(lèi)的三個(gè)習(xí):來(lái)學(xué)voidnotify()喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程。notifyAll()喚醒在此對(duì)象監(jiān)視器上等待的所有線程。wait()導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對(duì)象的voidvoidnotify()或notifyAll()。當(dāng)然,wait()還有另外兩個(gè)重載void wait(long timeout):導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對(duì)象的notify()或notifyAll(),或

51、者超過(guò)指定的時(shí)間量。void wait(long timeout, int nanos)導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對(duì)象的notify()或notifyAll() 量。,或者其他某個(gè)線斷當(dāng)前線程,或者已超過(guò)某個(gè)實(shí)際時(shí)間以上這些是幫助線程傳遞線程關(guān)心的時(shí)間狀態(tài)。關(guān)于等待/通知,要記住的關(guān)鍵點(diǎn)是:必須從同步環(huán)境內(nèi)調(diào)用wait()、notify()、notifyAll()。線程不能調(diào)用對(duì)象上等待或通知的,除非它擁有那個(gè)對(duì)象的鎖。wait()、notify()、notifyAll()都是 Object 的實(shí)例。與每個(gè)對(duì)象具有鎖一樣,每個(gè)對(duì)象可以有一個(gè)線程列表,他 們等待來(lái)自該信號(hào)(通知)。線程通過(guò)32Crazy Cabbage瘋狂大白菜執(zhí)行對(duì)象上的wai

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論