亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? chapter14.htm

?? Thinking In Java第二版(中文)
?? HTM
?? 第 1 頁 / 共 5 頁
字號:
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Thinking in Java | Chinese Version by Trans Bot</title>

<meta name="Microsoft Theme" content="inmotion 111, default"></head>

<body background="../_themes/inmotion/inmtextb.gif" tppabs="http://member.netease.com/%7etransbot/Thinking%20in%20Java/_themes/inmotion/inmtextb.gif" bgcolor="#FFFFCC" text="#000000" link="#800000" vlink="#996633" alink="#FF3399">

<p>第14章 多線程<br>
<br>
利用對象,可將一個程序分割成相互獨立的區域。我們通常也需要將一個程序轉換成多個獨立運行的子任務。<br>
象這樣的每個子任務都叫作一個“線程”(Thread)。編寫程序時,可將每個線程都想象成獨立運行,而且都有自己的專用CPU。一些基礎機制實際會為我們自動分割CPU的時間。我們通常不必關心這些細節問題,所以多線程的代碼編寫是相當簡便的。<br>
這時理解一些定義對以后的學習狠有幫助。“進程”是指一種“自包容”的運行程序,有自己的地址空間。“多任務”操作系統能同時運行多個進程(程序)——但實際是由于CPU分時機制的作用,使每個進程都能循環獲得自己的CPU時間片。但由于輪換速度非常快,使得所有程序好象是在“同時”運行一樣。“線程”是進程內部單一的一個順序控制流。因此,一個進程可能容納了多個同時執行的線程。<br>
多線程的應用范圍很廣。但在一般情況下,程序的一些部分同特定的事件或資源聯系在一起,同時又不想為它而暫停程序其他部分的執行。這樣一來,就可考慮創建一個線程,令其與那個事件或資源關聯到一起,并讓它獨立于主程序運行。一個很好的例子便是“Quit”或“退出”按鈕——我們并不希望在程序的每一部分代碼中都輪詢這個按鈕,同時又希望該按鈕能及時地作出響應(使程序看起來似乎經常都在輪詢它)。事實上,多線程最主要的一個用途就是構建一個“反應靈敏”的用戶界面。<br>
<br>
14.1 反應靈敏的用戶界面<br>
作為我們的起點,請思考一個需要執行某些CPU密集型計算的程序。由于CPU“全心全意”為那些計算服務,所以對用戶的輸入十分遲鈍,幾乎沒有什么反應。在這里,我們用一個合成的applet/application(程序片/應用程序)來簡單顯示出一個計數器的結果:<br>
<br>
752-753頁程序<br>
<br>
在這個程序中,AWT和程序片代碼都應是大家熟悉的,第13章對此已有很詳細的交待。go()方法正是程序全心全意服務的對待:將當前的count(計數)值置入TextField(文本字段)t,然后使count增值。<br>
go()內的部分無限循環是調用sleep()。sleep()必須同一個Thread(線程)對象關聯到一起,而且似乎每個應用程序都有部分線程同它關聯(事實上,Java本身就是建立在線程基礎上的,肯定有一些線程會伴隨我們寫的應用一起運行)。所以無論我們是否明確使用了線程,都可利用Thread.currentThread()產生由程序使用的當前線程,然后為那個線程調用sleep()。注意,Thread.currentThread()是Thread類的一個靜態方法。<br>
注意sleep()可能“擲”出一個InterruptException(中斷違例)——盡管產生這樣的違例被認為是中止線程的一種“惡意”手段,而且應該盡可能地杜絕這一做法。再次提醒大家,違例是為異常情況而產生的,而不是為了正常的控制流。在這里包含了對一個“睡眠”線程的中斷,以支持未來的一種語言特性。<br>
一旦按下start按鈕,就會調用go()。研究一下go(),你可能會很自然地(就象我一樣)認為它該支持多線程,因為它會進入“睡眠”狀態。也就是說,盡管方法本身“睡著”了,CPU仍然應該忙于監視其他按鈕“按下”事件。但有一個問題,那就是go()是永遠不會返回的,因為它被設計成一個無限循環。這意味著actionPerformed()根本不會返回。由于在第一個按鍵以后便陷入actionPerformed()中,所以程序不能再對其他任何事件進行控制(如果想出來,必須以某種方式“殺死”進程——最簡便的方式就是在控制臺窗口按Ctrl+C鍵)。<br>
這里最基本的問題是go()需要繼續執行自己的操作,而與此同時,它也需要返回,以便actionPerformed()能夠完成,而且用戶界面也能繼續響應用戶的操作。但對象go()這樣的傳統方法來說,它卻不能在繼續的同時將控制權返回給程序的其他部分。這聽起來似乎是一件不可能做到的事情,就象CPU必須同時位于兩個地方一樣,但線程可以解決一切。“線程模型”(以及Java中的編程支持)是一種程序編寫規范,可在單獨一個程序里實現幾個操作的同時進行。根據這一機制,CPU可為每個線程都分配自己的一部分時間。每個線程都“感覺”自己好象擁有整個CPU,但CPU的計算時間實際卻是在所有線程間分攤的。<br>
線程機制多少降低了一些計算效率,但無論程序的設計,資源的均衡,還是用戶操作的方便性,都從中獲得了巨大的利益。綜合考慮,這一機制是非常有價值的。當然,如果本來就安裝了多塊CPU,那么操作系統能夠自行決定為不同的CPU分配哪些線程,程序的總體運行速度也會變得更快(所有這些都要求操作系統以及應用程序的支持)。多線程和多任務是充分發揮多處理機系統能力的一種最有效的方式。<br>
<br>
14.1.1 從線程繼承<br>
為創建一個線程,最簡單的方法就是從Thread類繼承。這個類包含了創建和運行線程所需的一切東西。Thread最重要的方法是run()。但為了使用run(),必須對其進行過載或者覆蓋,使其能充分按自己的吩咐行事。因此,run()屬于那些會與程序中的其他線程“并發”或“同時”執行的代碼。<br>
下面這個例子可創建任意數量的線程,并通過為每個線程分配一個獨一無二的編號(由一個靜態變量產生),從而對不同的線程進行跟蹤。Thread的run()方法在這里得到了覆蓋,每通過一次循環,計數就減1——計數為0時則完成循環(此時一旦返回run(),線程就中止運行)。<br>
<br>
755頁程序<br>
<br>
run()方法幾乎肯定含有某種形式的循環——它們會一直持續到線程不再需要為止。因此,我們必須規定特定的條件,以便中斷并退出這個循環(或者在上述的例子中,簡單地從run()返回即可)。run()通常采用一種無限循環的形式。也就是說,通過阻止外部發出對線程的stop()或者destroy()調用,它會永遠運行下去(直到程序完成)。<br>
在main()中,可看到創建并運行了大量線程。Thread包含了一個特殊的方法,叫作start(),它的作用是對線程進行特殊的初始化,然后調用run()。所以整個步驟包括:調用構建器來構建對象,然后用start()配置線程,再調用run()。如果不調用start()——如果適當的話,可在構建器那樣做——線程便永遠不會啟動。<br>
下面是該程序某一次運行的輸出(注意每次運行都會不同):<br>
<br>
756頁程序<br>
<br>
可注意到這個例子中到處都調用了sleep(),然而輸出結果指出每個線程都獲得了屬于自己的那一部分CPU執行時間。從中可以看出,盡管sleep()依賴一個線程的存在來執行,但卻與允許或禁止線程無關。它只不過是另一個不同的方法而已。<br>
亦可看出線程并不是按它們創建時的順序運行的。事實上,CPU處理一個現有線程集的順序是不確定的——除非我們親自介入,并用Thread的setPriority()方法調整它們的優先級。<br>
main()創建Thread對象時,它并未捕獲任何一個對象的句柄。普通對象對于垃圾收集來說是一種“公平競賽”,但線程卻并非如此。每個線程都會“注冊”自己,所以某處實際存在著對它的一個引用。這樣一來,垃圾收集器便只好對它“瞠目以對”了。<br>
<br>
14.1.2 針對用戶界面的多線程<br>
現在,我們也許能用一個線程解決在Counter1.java中出現的問題。采用的一個技巧便是在一個線程的run()方法中放置“子任務”——亦即位于go()內的循環。一旦用戶按下Start按鈕,線程就會啟動,但馬上結束線程的創建。這樣一來,盡管線程仍在運行,但程序的主要工作卻能得以繼續(等候并響應用戶界面的事件)。下面是具體的代碼:<br>
<br>
757-759頁程序<br>
<br>
現在,Counter2變成了一個相當直接的程序,它的唯一任務就是設置并管理用戶界面。但假若用戶現在按下Start按鈕,卻不會真正調用一個方法。此時不是創建類的一個線程,而是創建SeparateSubTask,然后繼續Counter2事件循環。注意此時會保存SeparateSubTask的句柄,以便我們按下onOff按鈕的時候,能正常地切換位于SeparateSubTask內部的runFlag(運行標志)。隨后那個線程便可啟動(當它看到標志的時候),然后將自己中止(亦可將SeparateSubTask設為一個內部類來達到這一目的)。<br>
SeparateSubTask類是對Thread的一個簡單擴展,它帶有一個構建器(其中保存了Counter2句柄,然后通過調用start()來運行線程)以及一個run()——本質上包含了Counter1.java的go()內的代碼。由于SeparateSubTask知道自己容納了指向一個Counter2的句柄,所以能夠在需要的時候介入,并訪問Counter2的TestField(文本字段)。<br>
按下onOff按鈕,幾乎立即能得到正確的響應。當然,這個響應其實并不是“立即”發生的,它畢竟和那種由“中斷”驅動的系統不同。只有線程擁有CPU的執行時間,并注意到標記已發生改變,計數器才會停止。<br>
<br>
1. 用內部類改善代碼<br>
下面說說題外話,請大家注意一下SeparateSubTask和Counter2類之間發生的結合行為。SeparateSubTask同Counter2“親密”地結合到了一起——它必須持有指向自己“父”Counter2對象的一個句柄,以便自己能回調和操縱它。但兩個類并不是真的合并為單獨一個類(盡管在下一節中,我們會講到Java確實提供了合并它們的方法),因為它們各自做的是不同的事情,而且是在不同的時間創建的。但不管怎樣,它們依然緊密地結合到一起(更準確地說,應該叫“聯合”),所以使程序代碼多少顯得有些笨拙。在這種情況下,一個內部類可以顯著改善代碼的“可讀性”和執行效率:<br>
<br>
759-761頁程序<br>
<br>
這個SeparateSubTask名字不會與前例中的SeparateSubTask沖突——即使它們都在相同的目錄里——因為它已作為一個內部類隱藏起來。大家亦可看到內部類被設為private(私有)屬性,這意味著它的字段和方法都可獲得默認的訪問權限(run()除外,它必須設為public,因為它在基礎類中是公開的)。除Counter2i之外,其他任何方面都不可訪問private內部類。而且由于兩個類緊密結合在一起,所以很容易放寬它們之間的訪問限制。在SeparateSubTask中,我們可看到invertFlag()方法已被刪去,因為Counter2i現在可以直接訪問runFlag。<br>
此外,注意SeparateSubTask的構建器已得到了簡化——它現在唯一的用外就是啟動線程。Counter2i對象的句柄仍象以前那樣得以捕獲,但不再是通過人工傳遞和引用外部對象來達到這一目的,此時的內部類機制可以自動照料它。在run()中,可看到對t的訪問是直接進行的,似乎它是SeparateSubTask的一個字段。父類中的t字段現在可以變成private,因為SeparateSubTask能在未獲任何特殊許可的前提下自由地訪問它——而且無論如何都該盡可能地把字段變成“私有”屬性,以防來自類外的某種力量不慎地改變它們。<br>
無論在什么時候,只要注意到類相互之間結合得比較緊密,就可考慮利用內部類來改善代碼的編寫與維護。<br>
<br>
14.1.3 用主類合并線程<br>
在上面的例子中,我們看到線程類(Thread)與程序的主類(Main)是分隔開的。這樣做非常合理,而且易于理解。然而,還有另一種方式也是經常要用到的。盡管它不十分明確,但一般都要更簡潔一些(這也解釋了它為什么十分流行)。通過將主程序類變成一個線程,這種形式可將主程序類與線程類合并到一起。由于對一個GUI程序來說,主程序類必須從Frame或Applet繼承,所以必須用一個接口加入額外的功能。這個接口叫作Runnable,其中包含了與Thread一致的基本方法。事實上,Thread也實現了Runnable,它只指出有一個run()方法。<br>
對合并后的程序/線程來說,它的用法不是十分明確。當我們啟動程序時,會創建一個Runnable(可運行的)對象,但不會自行啟動線程。線程的啟動必須明確進行。下面這個程序向我們演示了這一點,它再現了Counter2的功能:<br>
<br>
762-763頁程序1<br>
<br>
現在run()位于類內,但它在init()結束以后仍處在“睡眠”狀態。若按下啟動按鈕,線程便會用多少有些曖昧的表達方式創建(若線程尚不存在):<br>
new Thread(Counter3.this);<br>
若某樣東西有一個Runnable接口,實際只是意味著它有一個run()方法,但不存在與之相關的任何特殊東西——它不具有任何天生的線程處理能力,這與那些從Thread繼承的類是不同的。所以為了從一個Runnable對象產生線程,必須單獨創建一個線程,并為其傳遞Runnable對象;可為其使用一個特殊的構建器,并令其采用一個Runnable作為自己的參數使用。隨后便可為那個線程調用start(),如下所示:<br>
selfThread.start();<br>
它的作用是執行常規初始化操作,然后調用run()。<br>
Runnable接口最大的一個優點是所有東西都從屬于相同的類。若需訪問什么東西,只需簡單地訪問它即可,不需要涉及一個獨立的對象。但為這種便利也是要付出代價的——只可為那個特定的對象運行單獨一個線程(盡管可創建那種類型的多個對象,或者在不同的類里創建其他對象)。<br>
注意Runnable接口本身并不是造成這一限制的罪魁禍首。它是由于Runnable與我們的主類合并造成的,因為每個應用只能主類的一個對象。<br>
<br>
14.1.4 制作多個線程<br>

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
午夜精品久久一牛影视| 国产欧美精品国产国产专区 | 成人激情午夜影院| 精品一区二区三区在线播放视频 | 精品综合免费视频观看| 日韩激情一区二区| 日韩1区2区日韩1区2区| 日韩1区2区日韩1区2区| 久久97超碰国产精品超碰| 久久97超碰国产精品超碰| 国产乱码精品一区二区三区忘忧草 | 美脚の诱脚舐め脚责91| 男男视频亚洲欧美| 国产专区欧美精品| 成人午夜又粗又硬又大| kk眼镜猥琐国模调教系列一区二区| 北条麻妃一区二区三区| 在线一区二区三区四区五区| 欧美日本在线观看| 中文字幕一区二区三区视频| 亚洲欧美日韩中文播放| 亚洲线精品一区二区三区八戒| 午夜久久电影网| 极品少妇一区二区三区精品视频 | 亚洲欧美激情视频在线观看一区二区三区 | 国产一区二区三区免费| 成人免费视频播放| 91精品国产91久久久久久最新毛片| 久久在线免费观看| 一区二区国产视频| 久久国产麻豆精品| 色婷婷av一区二区三区之一色屋| 555www色欧美视频| 国产欧美一二三区| 午夜免费久久看| 高清国产一区二区| 欧美视频自拍偷拍| 国产清纯白嫩初高生在线观看91| 一区二区在线电影| 国精产品一区一区三区mba桃花 | 欧美日韩一级二级三级| 国产清纯白嫩初高生在线观看91| 亚洲无线码一区二区三区| 国产精品一区久久久久| 欧美精品1区2区3区| 国产精品丝袜在线| 婷婷夜色潮精品综合在线| 成人v精品蜜桃久久一区| 欧美一区二区成人6969| 亚洲欧美一区二区三区孕妇| 国产精品资源在线观看| 日韩你懂的在线播放| 国产精品一级在线| 欧美猛男gaygay网站| 亚洲婷婷国产精品电影人久久| 青青草伊人久久| 欧美日韩视频第一区| 最新欧美精品一区二区三区| 国产精一区二区三区| 欧美不卡一区二区三区| 天天综合日日夜夜精品| 欧美少妇一区二区| 亚洲综合久久久| 一本久道久久综合中文字幕| 国产精品―色哟哟| 高清国产一区二区| 国产欧美精品一区| 国产乱码精品一区二区三区五月婷| 欧美一级二级在线观看| 日韩二区在线观看| 日韩无一区二区| 日日摸夜夜添夜夜添精品视频| 欧美综合在线视频| 亚洲国产成人av网| 欧美日本国产视频| 男女性色大片免费观看一区二区 | 91啪亚洲精品| 亚洲视频电影在线| 91尤物视频在线观看| 激情综合色综合久久| 日韩欧美亚洲国产另类| 极品尤物av久久免费看| 久久久久久久久99精品| 成人97人人超碰人人99| 亚洲欧美日韩人成在线播放| 欧美在线色视频| 免费高清成人在线| 久久婷婷一区二区三区| 9久草视频在线视频精品| 亚洲一区二区在线免费看| 欧美日韩国产精选| 韩国av一区二区三区四区 | 欧美日韩一区二区三区在线看| 午夜欧美视频在线观看| 久久人人97超碰com| 成人aa视频在线观看| 亚洲午夜精品久久久久久久久| 欧美一级欧美三级在线观看| 久草热8精品视频在线观看| 国产精品久久久久久一区二区三区| 91久久精品国产91性色tv| 亚洲国产日韩av| 2024国产精品视频| 在线免费一区三区| 国产一区二区三区四区五区美女| 国产精品视频麻豆| 欧美精品在线一区二区三区| 国产精品综合一区二区三区| 亚洲精品免费播放| 亚洲一区二区在线播放相泽| 欧美一卡二卡在线| 色综合久久中文综合久久97| 视频一区二区三区在线| 中文字幕一区不卡| 欧美精品一区二区三区蜜臀| 色成人在线视频| 高清不卡一区二区| 久久er精品视频| 亚洲午夜羞羞片| 国产精品三级久久久久三级| 日韩一区二区麻豆国产| 色婷婷久久久久swag精品| 国产一区二区三区在线观看免费| 亚洲免费观看高清完整| 国产日产欧产精品推荐色| 欧美伊人久久久久久午夜久久久久| 国产精品888| 奇米色一区二区三区四区| 亚洲精品水蜜桃| 国产欧美一区二区精品婷婷| 日韩欧美中文字幕制服| 欧美日韩视频专区在线播放| 99国产精品视频免费观看| 国产成人精品综合在线观看| 蜜臀久久99精品久久久久久9| 国产91清纯白嫩初高中在线观看| 日韩成人dvd| 午夜精品123| 亚洲一区二区三区影院| 亚洲免费资源在线播放| 日韩久久一区二区| 国产精品久久久久精k8| 日本一区二区三区dvd视频在线| 精品国产一区二区精华| 日韩午夜在线观看视频| 日韩一区二区电影网| 9191精品国产综合久久久久久| 欧美影视一区在线| 欧美偷拍一区二区| 色婷婷av久久久久久久| 一本大道久久a久久精品综合| 99久久久精品| 日本韩国欧美三级| 在线免费精品视频| 欧美日韩国产成人在线91| 欧美精品tushy高清| 欧美成人性福生活免费看| 欧美成人video| 日本一区二区三区四区在线视频| 国产精品久久看| 亚洲制服丝袜av| 日韩va欧美va亚洲va久久| 偷拍一区二区三区四区| 激情欧美日韩一区二区| 国产经典欧美精品| 99re这里只有精品6| 色爱区综合激月婷婷| 51精品视频一区二区三区| 欧美不卡一区二区三区四区| 久久精品一区二区三区不卡 | 国产午夜亚洲精品午夜鲁丝片 | av动漫一区二区| 日本精品视频一区二区| 欧美午夜免费电影| 日韩视频免费观看高清在线视频| 欧美成人精品高清在线播放| 欧美激情艳妇裸体舞| 亚洲一区av在线| 美女www一区二区| a级精品国产片在线观看| 欧美熟乱第一页| 26uuu国产在线精品一区二区| 欧美激情综合网| 亚洲成av人片www| 国产精品一区二区视频| 91极品美女在线| 精品国产sm最大网站免费看| 最好看的中文字幕久久| 青椒成人免费视频| 91麻豆免费观看| 精品国产一区a| 亚洲成av人片在线观看无码| 国产伦精品一区二区三区免费迷 | 久久电影网站中文字幕| av一二三不卡影片| 日韩免费高清av| 亚洲精品高清在线| 国产成人精品免费| 日韩欧美国产不卡| 亚洲最快最全在线视频|