日本亚洲欧美日韩中文字幕_精品欧美一区二区三区久久久_久久av高潮av无码av_成在人线av无码免费_亚洲中文字幕无码久久精品1

13140882082

全國統(tǒng)一學(xué)習(xí)專線 8:30-21:00

南寧達(dá)內(nèi):編寫多線程Java應(yīng)用程序常見問題

 

  幾乎所有使用 AWT 或 Swing 編寫的畫圖程序都需要多線程。但多線程程序會(huì)造成許多困難,剛開始編程的開發(fā)者常常會(huì)發(fā)現(xiàn)他們被一些問題所折磨,例如不正確的程序行為或死鎖。

  在本文中,我們將探討使用多線程時(shí)遇到的問題,并提出那些常見陷阱的解決方案。

  線程是什么?

  一個(gè)程序或進(jìn)程能夠包含多個(gè)線程,這些線程可以根據(jù)程序的代碼執(zhí)行相應(yīng)的指令。多線程看上去似乎在并行執(zhí)行它們各自的工作,就像在一臺計(jì)算機(jī)上運(yùn)行著多個(gè)處理機(jī)一樣。在多處理機(jī)計(jì)算機(jī)上實(shí)現(xiàn)多線程時(shí),它們確實(shí)可以并行工作。和進(jìn)程不同的是,線程共享地址空間。也就是說,多個(gè)線程能夠讀寫相同的變量或數(shù)據(jù)結(jié)構(gòu)。

  編寫多線程程序時(shí),你必須注意每個(gè)線程是否干擾了其他線程的工作??梢詫⒊绦蚩醋饕粋€(gè)辦公室,如果不需要共享辦公室資源或與其他人交流,所有職員就會(huì)獨(dú)立并行地工作。某個(gè)職員若要和其他人交談,當(dāng)且僅當(dāng)該職員在“聽”且他們兩說同樣的語言。此外,只有在復(fù)印機(jī)空閑且處于可用狀態(tài)(沒有僅完成一半的復(fù)印工作,沒有紙張阻塞等問題)時(shí),職員才能夠使用它。在這篇文章中你將看到,在 Java 程序中互相協(xié)作的線程就好像是在一個(gè)組織良好的機(jī)構(gòu)中工作的職員。

  在多線程程序中,線程可以從準(zhǔn)備就緒隊(duì)列中得到,并在可獲得的系統(tǒng) CPU 上運(yùn)行。操作系統(tǒng)可以將線程從處理器移到準(zhǔn)備就緒隊(duì)列或阻塞隊(duì)列中,這種情況可以認(rèn)為是處理器“掛起”了該線程。同樣,Java 虛擬機(jī) (JVM) 也可以控制線程的移動(dòng)--在協(xié)作或搶先模型中--從準(zhǔn)備就緒隊(duì)列中將進(jìn)程移到處理器中,于是該線程就可以開始執(zhí)行它的程序代碼。

  協(xié)作式線程模型允許線程自己決定什么時(shí)候放棄處理器來等待其他的線程。程序開發(fā)員可以精確地決定某個(gè)線程何時(shí)會(huì)被其他線程掛起,允許它們與對方有效地合作。缺點(diǎn)在于某些惡意或是寫得不好的線程會(huì)消耗所有可獲得的 CPU 時(shí)間,導(dǎo)致其他線程“饑餓”.

  在搶占式線程模型中,操作系統(tǒng)可以在任何時(shí)候打斷線程。通常會(huì)在它運(yùn)行了一段時(shí)間(就是所謂的一個(gè)時(shí)間片)后才打斷它。這樣的結(jié)果自然是沒有線程能夠不公平地長時(shí)間霸占處理器。然而,隨時(shí)可能打斷線程就會(huì)給程序開發(fā)員帶來其他麻煩。同樣使用辦公室的例子,假設(shè)某個(gè)職員搶在另一人前使用復(fù)印機(jī),但打印工作在未完成的時(shí)候離開了,另一人接著使用復(fù)印機(jī)時(shí),該復(fù)印機(jī)上可能就還有先前那名職員留下來的資料。搶占式線程模型要求線程正確共享資源,協(xié)作式模型卻要求線程共享執(zhí)行時(shí)間。由于 JVM 規(guī)范并沒有特別規(guī)定線程模型,Java 開發(fā)員必須編寫可在兩種模型上正確運(yùn)行的程序。在了解線程以及線程間通訊的一些方面之后,我們可以看到如何為這兩種模型設(shè)計(jì)程序。

  線程和 Java 語言

  為了使用 Java 語言創(chuàng)建線程,你可以生成一個(gè) Thread 類(或其子類)的對象,并給這個(gè)對象發(fā)送 start() 消息。(程序可以向任何一個(gè)派生自 Runnable 接口的類對象發(fā)送 start() 消息。)每個(gè)線程動(dòng)作的定義包含在該線程對象的 run() 方法中。run 方法就相當(dāng)于傳統(tǒng)程序中的 main() 方法;線程會(huì)持續(xù)運(yùn)行,直到 run() 返回為止,此時(shí)該線程便死了。

  上鎖

  大多數(shù)應(yīng)用程序要求線程互相通信來同步它們的動(dòng)作。在 Java 程序中最簡單實(shí)現(xiàn)同步的方法就是上鎖。為了防止同時(shí)訪問共享資源,線程在使用資源的前后可以給該資源上鎖和開鎖。假想給復(fù)印機(jī)上鎖,任一時(shí)刻只有一個(gè)職員擁有鑰匙。若沒有鑰匙就不能使用復(fù)印機(jī)。給共享變量上鎖就使得 Java 線程能夠快速方便地通信和同步。某個(gè)線程若給一個(gè)對象上了鎖,就可以知道沒有其他線程能夠訪問該對象。即使在搶占式模型中,其他線程也不能夠訪問此對象,直到上鎖的線程被喚醒、完成工作并開鎖。那些試圖訪問一個(gè)上鎖對象的線程通常會(huì)進(jìn)入睡眠狀態(tài),直到上鎖的線程開鎖。一旦鎖被打開,這些睡眠進(jìn)程就會(huì)被喚醒并移到準(zhǔn)備就緒隊(duì)列中。

  在 Java 編程中,所有的對象都有鎖。線程可以使用 synchronized 關(guān)鍵字來獲得鎖。在任一時(shí)刻對于給定的類的實(shí)例,方法或同步的代碼塊只能被一個(gè)線程執(zhí)行。這是因?yàn)榇a在執(zhí)行之前要求獲得對象的鎖。繼續(xù)我們關(guān)于復(fù)印機(jī)的比喻,為了避免復(fù)印沖突,我們可以簡單地對復(fù)印資源實(shí)行同步。如同下列的代碼例子,任一時(shí)刻只允許一位職員使用復(fù)印資源。通過使用方法(在 Copier 對象中)來修改復(fù)印機(jī)狀態(tài)。這個(gè)方法就是同步方法。只有一個(gè)線程能夠執(zhí)行一個(gè) Copier 對象中同步代碼,因此那些需要使用 Copier 對象的職員就必須排隊(duì)等候。

  class CopyMachine {

  public synchronized void makeCopies(Document d, int nCopies) {

  // only one thread executes this at a time

  }

  public void loadPaper() {

  // multiple threads could access this at once!

  synchronized(this) {

  // only one thread accesses this at a time

  // feel free to use shared resources, overwrite members, etc.

  }

  }

  }

  Fine-grain 鎖

  在對象級使用鎖通常是一種比較粗糙的方法。為什么要將整個(gè)對象都上鎖,而不允許其他線程短暫地使用對象中其他同步方法來訪問共享資源?如果一個(gè)對象擁有多個(gè)資源,就不需要只為了讓一個(gè)線程使用其中一部分資源,就將所有線程都鎖在外面。由于每個(gè)對象都有鎖,可以如下所示使用虛擬對象來上鎖:

  class FineGrainLock {

  MyMemberClass x, y;

  Object xlock = new Object(), ylock = new Object();

  public void foo() {

  synchronized(xlock) {

  // access x here

  }

  // do something here - but don't use shared resources

  synchronized(ylock) {

  // access y here

  }

  }

  public void bar() {

  synchronized(this) {

  // access both x and y here

  }

  // do something here - but don't use shared resources

  }

  }

  若為了在方法級上同步,不能將整個(gè)方法聲明為 synchronized 關(guān)鍵字。它們使用的是成員鎖,而不是 synchronized 方法能夠獲得的對象級鎖。

  信號量

  通常情況下,可能有多個(gè)線程需要訪問數(shù)目很少的資源。假想在服務(wù)器上運(yùn)行著若干個(gè)回答客戶端請求的線程。這些線程需要連接到同一數(shù)據(jù)庫,但任一時(shí)刻只能獲得一定數(shù)目的數(shù)據(jù)庫連接。你要怎樣才能夠有效地將這些固定數(shù)目的數(shù)據(jù)庫連接分配給大量的線程?一種控制訪問一組資源的方法(除了簡單地上鎖之外),就是使用眾所周知的信號量計(jì)數(shù) (counting semaphore)。信號量計(jì)數(shù)將一組可獲得資源的管理封裝起來。信號量是在簡單上鎖的基礎(chǔ)上實(shí)現(xiàn)的,相當(dāng)于能令線程安全執(zhí)行,并初始化為可用資源個(gè)數(shù)的計(jì)數(shù)器。例如我們可以將一個(gè)信號量初始化為可獲得的數(shù)據(jù)庫連接個(gè)數(shù)。一旦某個(gè)線程獲得了信號量,可獲得的數(shù)據(jù)庫連接數(shù)減一。線程消耗完資源并釋放該資源時(shí),計(jì)數(shù)器就會(huì)加一。當(dāng)信號量控制的所有資源都已被占用時(shí),若有線程試圖訪問此信號量,則會(huì)進(jìn)入阻塞狀態(tài),直到有可用資源被釋放。

  信號量最常見的用法是解決“消費(fèi)者-生產(chǎn)者問題&rdqu

溫馨提示:為不影響您的學(xué)業(yè),來校區(qū)前請先電話咨詢,方便我校安排相關(guān)的專業(yè)老師為您解答
  • 熱門課程
  • 作者最新文章
  • 在線報(bào)名
申請?jiān)嚶犝n程

只要一個(gè)電話
我們免費(fèi)為您回電

姓名不能為空
手機(jī)號格式錯(cuò)誤