欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

多線程編程

系統 1713 0
多線程是Java程序設計語言的一個亮點,它使用戶可以很方便地編寫多線程程序,雖然編寫多線程代碼需要考慮諸如安全、死鎖、資源共享的問題,但是總體上講Java在編寫多線程程序上比其他語言都要簡潔。
使用多線程最直接的例子是具有用戶界面的程序。如果用戶界面上設計了一個按鈕,一旦單擊該按鈕程序會自動在網絡上搜索指定數據,當然這個過程會持續一段時間。如果沒有多線程實現技術,就會出現用戶界面無法控制的局面,即在網絡數據搜索完之前,用戶界面根本不響應其他界面輸入。整個界面象是靜止在那里而無法操作。而我們希望不管系統當前在完成什么任務,都允許用戶操作界面元素,如查詢數據,完成其他信息的處理等。這樣就要求程序可以同時執行多個任務,響應用戶的不同操作請求。對于用戶而言就仿佛有多個處理器在為其工作。而在單處理器的計算機上完成程序的多任務功能就需要多線程技術。
多線程技術可以模擬多處理器的效果,對用戶而言計算機同時完成一個程序的多個任務,而實際上該機制使得計算機把CPU周期按照一定策略分配給每一個線程,而高速的CPU使得用戶覺得計算機在同時完成多個任務。
9.1? 線程概述
線程是操作系統的概念,線程也稱之為輕量級進程(lightweight process LWP),是CPU的基本使用單元,它的輕量級名稱是和進程相關的。線程由線程ID、程序記數器、寄存器和堆棧組成,多個線程可以共享代碼段、數據段和諸如打開的文件等的系統資源。而傳統的進程其實就是單線程控制程序,每個進程都有自己的代碼段、數據段和其他系統資源。這無疑使得每個進程管理更多的內容,從而稱為重量級進程。“輕量”是指線程沒有獨自的存儲空間,和同一個進程的多個線程共享存儲空間。
多線程和傳統的單線程在程序設計上的最大區別是每個線程獨自運行,是彼此獨立的指令流,造成線程之間的執行是亂序的,所以線程的控制需要謹慎對待。
下面分別詳細介紹進程和線程的概念,如何創建線程、設置線程的優先級、線程控制和線程同步等關鍵問題。
9.2? 創建線程
在學習線程前,一定要先了解Java的線程機制,然后學習如何利用Thread類實現多線程。Java的多線程機制提供了兩種方式實現多線程編程,一種是通過繼承java.long.Thread類來實現,一種是通過實現Runnable接口實現。
9.2.1? 繼承Thread類創建線程
Thread類是Java實現多線程的提供了簡單的方法,Thread類已經具備了運行多線程所需要的資源,用戶只需要重載該類的run()方法,把需要使用多線程運行的代碼放入該方法。這樣這些代碼就可以和其他線程“同時”存在。創建線程對象并用該對象調用start()方法則線程開始運行,start()方法提供了啟動線程和線程運行所需要的框架。
代碼是一個例子,說明使用繼承 Thread類實現多線程。每次new一個線程都設置一個線程計數器,表明建立的線程數。整個程序啟動3個線程,每個線程會有9次輸出,但是三個線程的建立并非順序執行,而每個線程的9次輸出也不一定會順序輸出。如代碼繼承Thread類實現多線程示例所示。
9.2.2? 實現Runnable接口創建線程
Java提供了另一個有用的接口實現多線程編程。因為Java不支持多繼承,所以如果用戶的類已經繼承了一個類,而又需要多線程機制的支持,此時繼承thread類就不現實了。所以Runnable接口在這種情況下就很實用。
Runnable 接口有唯一一個方法run(),所以實現該接口時必須自己定義該方法,提供多線程需要執行的代碼。如果運行通過實現Runnable接口的多線程程序,則需要借助Thread類,因為Runnable接口沒有提供任何東西支持多線程,必須借助Thead類的框架實現多線程,即通過類Thread的構造函數 public Thread(Runnable target)來實現。代碼是通過繼承Runnable接口而實現多線程的例子。我們分析和運行該程序,觀察輸出結果就可以很好的理解其運用。
9.3? 線程的狀態
在Java中線程的執行過程稍微有些復雜,但線程對象創建后并不不是立即執行,需要做些準備工作才有執行的權利,而一旦搶占到CPU周期,則線程可以運行,但CPU周期結束則線程必須暫時停止,或線程執行過程中的某個條件無法滿足時也會暫時停止,只有等待條件滿足時才會繼續執行,最后從run()方法返回后,線程退出。可以看出線程的執行過程中涉及一些狀態,線程就在這些狀態之間遷移。
做一點說明,Java 規范中只定義了線程的四種狀態,即新建狀態、可運行狀態、阻塞狀態和死亡狀態。為了更清晰的說明線程的狀態變化過程,我們認為劃分為五個狀態更好理解,這里把可運行狀態(Runnable)分解為就緒狀態和運行狀態,可以更好的理解可運行狀態的含義。
線程包括五個狀態:新建狀態、就緒狀態、運行狀態、阻塞狀態和死亡狀態。下面分別詳細介紹這五種狀態。
9.4? 線程的優先級
線程的有限級表示一個線程被CPU執行的機會多少。注意,這里用“機會多少”來表達而不是用“先后順序”來表達。在Java中雖然定義了設置線程優先級高低的方法,但是優先級低并不意味著在不同優先級的線程中就不會被執行,優先級低只說明該線程被執行的概率小,同理優先級高的線程獲得CPU的概率就大。
通過Tread類的setPriority()方法設置線程的優先級,該方法的參數為int型,其實 Java提供了三個優先級別,都為Thread類的常量,從高到低依次為Thread. MAX-PRIORITY、Thread.NORM_PRIORITY、Thread.MIN_PRIORITY。這里再次重申,優先級低并不意味著線程得不到執行,而是線程被優先執行的概率小。這也說明設置線程的優先級不會造成死鎖的發生。
9.5? 線程的同步
在多線程中經常遇到的一個問題就是資源共享問題,假設兩個線程同時訪問一個數據區,一個讀數據、一個寫數據,在一個線程讀數據前另一個線程修改了數據,則讀數據線程讀到的不是原始數據而是被修改過的數據,顯然這樣使不允許的。而在多線程編程中經常會遇到訪問共享資源的問題,這些資源可以是數據、文件、一塊內存區或是外圍設備的訪問等。所以必須解決多線程編程中如何實現資源的共享問題,在Java中稱為線程的同步問題,在多數的編程語言中解決共享資源沖突的方法是采用順序機制(Serialize),通過為共享資源加鎖的方法實現資源的順序訪問。
9.5.1? Java程序的資源共享
通過下面的例子,說明如果沒有實現線程同步的訪問共享資源會遇到的問題。我們設計一個線程類 FooOne,該類的多線程代碼無限循環的輸出一個值,每次循環該值遞增,但遞增到100時,停止循環線程退出,這由方法run()中調用方法 printVal()實現。另一個線程類FooTwo調用類FooOne的對象,該類的run()方法調用類FooOne對象的printVal()方法,也實現對變量的遞增輸出。我們希望是兩次調用各自完成變量的遞增,相互之間不要有干擾,即兩次調用要求順序執行。但事實上目前我們無法控制這種順序執行(隨后會介紹synchronized關鍵字解決這個問題)。所以結果是兩個線程交替執行,確實實現了并發,或者更抽象的說兩個線程同時訪問了某個資源,造成數據的不確定性。
9.5.2? synchronized關鍵字
在設計多線程模式中,解決線程沖突問題都是采用synchronize關鍵字實現的。這意味著在給定時刻只允許一個線程訪問共享資源。通常是在代碼前加上一條鎖語句實現的,這就保證了在一段時間內只有一個線程運行這段代碼,如果另一個線程需要訪問這段共享資源,必須等待當前的線程釋放鎖。可見鎖語句產生了一種互斥的效果,所以常常稱鎖為“互斥量”(mutex)。
要控制對共享資源的訪問,首先要把它封裝進一個類,即編寫一個方法來訪問共享資源,為了保證對象在調用該方法訪問資源時實現互斥訪問,必須提供保證機制,保證順序的訪問共享資源。一般來說類中的數據成員都被聲明為私有的,只有通過方法來訪問這些數據。所以可以把方法標記為synchronized來防止資源沖突。
9.5.3? 同步控制方法
修改代碼9-4的部分代碼,使用synchronized關鍵字修飾方法,實現對方法的順序訪問,代碼修改部分如下:
11 public synchronized void printVal(int v,String y){
12? while(v<10)
13? System.out.println(y+":"+v++);
14 }
這里只是在方法前增加了一個關鍵字,這就表示如果一個線程調用該方方法,則必須首先獲得方法所在類的對象的鎖,執行完后釋放鎖。下一個線程在訪問該方法前,先獲得鎖,然后再執行代碼,這樣就實現了對共享資源(或關鍵代碼)的順序訪問。保證了多線程的安全性。其執行結果為:

9.5.4? 同步控制塊
實際中會遇到這樣一種情況,兩個函數共享公共資源,為了使資源得到保護,必須實現資源訪問地同步控制,尤其是 static方法和非static方法共享資源的情況更是如此。此時可以使用同步控制塊來解決這個問題。代碼6同步控制塊示例顯示了具體用法。
代碼同步控制塊示例
1 class SynControlBlock implements Runnable{
2 private SomeObj obj
3 public static void method1(){
4? synchronized(obj){
5?? // 共享資源代碼
6? }
7 }
8 public void method2(){
9? synchronized(obj){
10?? // 共享資源代碼
11? }
12 }
13} 。
9.6? 線程的控制
線程是一個相對獨立的執行單元,完成一個具體的任務。線程的可以被創建、執行、阻塞、恢復執行、結束等行為,這些行為組成了線程的控制機制。本節介紹線程控制的內容、具體方法和實現方式。
9.6.1? 啟動線程
無論是通過繼承Thread類實現多線程還是通過實現Runnable接口實現多線程,如果要啟動線程都需要 Thread類的start()方法。該方法完成線程執行的一些初始化工作。假設一個多線程類繼承Thread實現,類名為MyThread,而另一個類實現Runnable接口設計多線程,類名為MyRunThread,則二者啟動線程方式如下:
1 //創建類MyThread的對象 thread,并啟動該線程。
2 MyThread thread = new MyThread();
3? thread.start()
4 // 創建類MyRunThread()的對象myRunThread,并啟動該線程。
5 Thread myRunThread = new Thread(new MyRunThread());
6? myRunThread.start();
9.6.2? 掛起和恢復線程
在Java2之前,用戶會看到suspend()和resume()用來阻塞和喚醒線程,但是在 Java2中這兩個方法不再使用了。首先分析一下使用suspend()方法會發生什么問題。suspend()方法的作用是掛起擁有鎖的線程,但是與 wait()方法不同,它不會釋放鎖。如果一線程調用suspend()方法,把另一個線程掛起,此時被掛起的線程在等待恢復,而掛起它的線程在等待獲得鎖(該鎖就是被掛起的線程對象),此時就會發生死鎖。
9.6.3? 線程的休眠
Java提供了一種控制線程的方法Sleep(int miliseconds),這里稱為線程的休眠,它將線程停止一段時間,該時間由方法的參數決定,當時間結束時線程進入就緒狀態,可以搶占CPU的時間周期。把例子代碼修改后觀察sleep()方法的作用,將得到代碼。

9.6.4? 等待和通知
等待和通知實現了線程之間的協調機制,使得線程之間可以建立“和諧”地協作關系。Java提供了線程對象的 wait()、notifty()或notifyAll()方法來實現這種協作,wait()方法使線程掛起一段時間,而notifty()或 notifyAll()方法使線程從wait()方法調用的狀態中恢復到就緒狀態。
Wait() 和sleep()方法相似,都是讓線程暫時掛起,都可以接受一個時間參數,確定線程掛起時間。但是wait()方法有其特殊之處。
(1)線程一旦調用wait()方法,線程中同步方法的鎖被釋放,別的線程可以調用該線程中相應的同步方法。
(2)使用wait()方法的線程可以使用 notifty()和notifyAll()方法獲得執行的權利,即獲得搶占CPU周期的權利。
9.6.5? 結束線程
在Java2中stop()方法不再被支持,在將來的版本中該方法可能被替換但是由于其天生的不安全性,替換的方法也不會取得好的效果。盡管在Java2中不再支持該方法,但Java 仍然包含了該API,也就是說程序員仍然可以調用該方法來結束線程。
但調用stop()方法終止一個線程時,會釋放該線程持有的所有鎖,而問題是用戶無法知道代碼目前的工作內容,這是導致stop()方法不安全的因素。如果通過謹慎的設計,或許可以實現安全的使用該方法。如果用戶知道在調用該方法時,線程沒有處在處理或更新其他對象或數據的狀態,則可以安全的使用該方法,但是有多少程序員會遇到這種情況呢,非常少。所以,多數情況下,用戶認為自己安全的使用了stop()方法來結束線程,往往造成不可預知的后果。
9.7? 線程間通信
線程間進行輸入輸出通信最常用的方式是“管道”方式。Java線程支持這種形式的通信。即一個線程從管道一端寫入數據,另一個線程從管道對端讀出數據,用戶不必關心管道是如何傳輸數據和實現管道兩端的線程通信的。在Java的輸入輸出類庫中兩個類 PipedWriter和PipedReader都支持管道通信方式。前者允許向管道寫數據,后者允許向不同的線程從同一個管道讀數據。下面分別介紹這連個類和相應的方法。
9.7.1? PipeWriter類詳解
該類的作用是創建一個PipedWriter類對象writer,鏈接到一個 PipedReader類對象reader,從writer寫入的數據從reader可以輕松讀出。該類的聲明方式有兩種。
public PipedWriter(PipedReader reader) throws IOException{/*類主體*/}
類的構造函數參數為 PipedReader類對象,明確了建立管道鏈接的兩個對象。
public PipedWriter() throws IOException{/*類主體*/}
9.7.2? 管道通信實例
代碼9-11說明了線程間通過管道通信的實現方式。該程序建立兩個類,一個類PipeSender負責向管道寫數據,一個類PipedReceiver負責從管道讀數據,但兩個線程都啟動后,負責讀數據的線程不斷的從管道讀數據,并打印到輸出屏幕上。
9.8? 多線程的死鎖問題
上節講了線程的各種控制,以及如何避免資源的共享訪問問題。這些方法使讀者可以很方便的控制線程,但是正如一枚硬幣的兩面,它同時也帶來了不利的一面,即死鎖問題。由于線程會進入阻塞狀態,并且對象同步鎖的存儲在,使得只有獲得對象的鎖才能訪問該對象。因此很容易發上循環死鎖。如線程A等待線程B釋放鎖,而線程B等待線程C釋放鎖,線程C有等待線程A釋放鎖,這樣就造成一個輪回等待。三個線程都無法繼續運行。
對于Java語言來講沒有很好地預防死鎖的方法,只有依靠讀者謹慎的設計來避免死鎖的發生。這里提供一個避免死鎖的基本原則。
(1)避免使用 suspend()和resume()方法,這些方法具有與生俱來產生死鎖的缺點。
(2)不要對長時間I/O操作的方法施加鎖。
(3)使用多個鎖時,確保所有線程都按相同的順序獲得鎖。
9.9? 多線程的缺點
多線程的主要目的是對大量并行的任務進行有序地管理。通過同時執行多個任務,可以有效的利用計算機的資源(主要是提高CPU的利用率),或者實現對用戶來講響應及時的程序界面。但是不可避免的任何“好東西”都有代價,所以使用多線程也有其缺點主要包括:
(1)等待訪問共享資源時使得程序運行變慢。如果用戶訪問網絡數據庫,而改善數據庫的訪問是互斥的,所以一個線程在訪問大量數據或修改大量數據時,其他線程就只用等待而不能執行,同時如果把網絡鏈接和數據傳輸的時間計算在內,則等待的時間或許是“不可忍受的”。
(2)當線程數量增多時,對線程的管理要求額外的CPU開銷。雖然線程是輕量級進程和其他線程共享一些數據,但是畢竟每個線程需要自己的管理資源,而這些資源的管理會耗費CPU時間片,如果線程數量增多到一定程度如(100個以上),則線程的管理開銷代價會增大。
(3)死鎖是難以避免的,只有依靠程序員謹慎地設計多線程程序。任何語言都不可能提供預防死鎖的方法,Java也不例外除了盡量不使用控制線程的一些方法如suspend(),resume()外,需要認真的分析線程的執行過程,以避免線程間的死鎖。
(4)隨意使用線程技術有時會耗費系統資源,所以要求程序員知道何時使用多線程以及何時避免使用該技術。
9.10? 習題
(1)簡答題
1.解釋線程的概念,線程和進程的區別是什么?
2.Java線程有幾中狀態,各狀態之間轉換的條件?
3.創建線程有幾種途徑,這些途徑如何具體實現線程。它們的使用場合有什么不同,二者的關系?
4.Java如何定義線程的優先級,優先級高的線程是否一定先于優先級低的線程執行,為什么?
5.使用Synchronized關鍵字可以實現鎖機制,實現資源的同步訪問,這里同步指什么?如何使用synchronized關鍵字?
6.線程等待和線程休眠都會使當前線程停止執行,而等待某個條件從而獲得繼續執行的機會,那么線程等待和線程休眠的區別在哪里?
7.線程間通信是通過管道流實現的,發送數據的線程把數據寫入管道,接收數據的線程把數據從管道讀出,Java是如何通過管道流機制實現的線程間通信的?
8.解釋線程控制中方法resume()和suspend()方法的功能, 為什么這兩種控制線程的方法容易引起線程的死鎖?
9.如何避免線程的死鎖?
(2)編程題
1.繼承Thread類編寫一個線程類,覆寫run()方法,每次啟動線程時打印一行輸入說明啟動的是第幾個線程。
2.編寫兩個線程類(繼承自Thread),一個資源類提供資源訪問的方法,包括一個讀數據方法一個寫數據方法,要求實現兩個線程對資源的互斥訪問。

多線程編程


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 99久久精品免费 | 天天干天天操天天射 | 日韩 欧美 自拍 | 国产成+人+综合+亚洲 欧美 | 91精品啪国产在线观看免费牛牛 | 国产精品人妻无码八区仙踪林 | 综合久久久 | 精品日韩欧美国产一区二区 | 精品国产日韩一区三区 | 久久中文字幕一区二区三区 | 国产中文字幕在线观看 | 亚洲天堂视频在线观看免费 | 波多野结衣的一级片 | 国产激爽大片高清在线观看 | 亚洲97| 日本高清免费不卡在线播放 | 欧美精品午夜久久久伊人 | 天天舔天天干天天操 | 狠狠久| 日韩精品不卡 | 国产成人福利在线视老湿机 | 久久久久久国产精品 | 成人免费在线视频观看 | 四色成人av永久网址 | 久久网精品视频 | 欧美一级黄色免费看 | 久久国产精品视频 | 人妖一区 | 欧美综合自拍亚洲综合网 | 成年免费大片黄在线观看岛国 | 久久精品国产清自在天天线 | 午夜视频在线观看网站 | 九九99国产精品视频 | 亚洲成av人片在线观看 | 日韩在线高清 | 色综合亚洲色综合久久网张柏芝 | 日本一视频一区视频二区 | 亚洲人性生活视频 | 啪啪免费网站 | 91精品国产免费久久久久久 | 国产国产精品人在线观看 |