| 導購 | 订阅 | 在线投稿
分享
 
 
 

線程基礎(第二部分)Java線程的缺陷和副作用幾解決辦法

來源:互聯網網民  2008-05-31 12:10:35  評論

Al Saganich / 翻譯:朱英

<--在線程基礎的第二部分中,我們將了解一下使用Java線程的缺陷和副作用,以及在SUN JDK 1.2中是如何修改線程的運行機制的-->

在上篇文章《Java 101之線程基礎》中,我們介紹了線程的概念以及如何使用線程。這個月,我們將轉到更高級的話題,包括線程的缺陷及副作用,以及在SUN JDK 1.2中,是如何改進線程的運行機制的。

synchronize(同步)

讓我們回憶一下上篇文章中講的:線程答應兩個或者更多個進程同時執行。實際上,這些線程也可以共享對象和數據,在這種情形下,你要知道不同的線程在同一時間內不能存取同一數據,因爲一開始設計Java的時候,就采用了線程的概念,Java語言定義了一個非凡的要害字synchronize(同步),該要害字可以應用到代碼塊上,代碼塊也包括入口方法,該要害字的目的是防止多個線程在同一時間執行同一代碼塊內的代碼。

定義一個同步的方法,格式如下:

[publicprivate] synchronized {type}

methodname(...)

一個把同步這個要害字應用到方法中的簡單的例子:

public class someClass {

public void aMethod() {

// Some code

synchronized(this) {

// Synchronized code block

}

// more code.

}

}

同步化的要害字可以保證在同一時間內只有一個線程可以執行該代碼段,而任何其他要用到該段代碼的線程將被阻塞,直到第一個線程執行完該段代碼。

死鎖和饑餓

對于饑餓的定義-由于別的並發的激活的過程持久占有所需資源,是莫個異步過程載客猜測的時間內不能被激活。

最常碰到的線程的兩個缺陷是死鎖和饑餓。當一個或者多個進程,在一個給定的任務中,協同作用,互相幹涉,而導致一個或者更多進程永遠等待下去,死鎖就發生了。與此類似,它當一個進程永久性地占有資源,使得其他進程得不到該資源,就發生了饑餓。

首先我們看一下死鎖問題。考慮一個簡單的例子,假如你到ATM機上取錢,但是你卻看到如下的信息「現在有沒有現金,請等會兒再試。」你需要錢,所以你就等了一會兒再試,但是你又看到同樣的信息。與此同時,在你後面,一輛運款裝甲車正等待著把錢放進ATM中,但是運款裝甲車到不了ATM取款機,因爲你的汽車擋著道。而你又要取到錢,才會離開原地。這種情況下,就發生了死鎖。

在饑餓的情形下,系統不處于死鎖狀態中,因爲有一個進程仍在處理之中,只是其他進程永遠得不到執行的機會。在什麽樣的環境下,會導致饑餓的發生,沒有預先確定好的規則。而一旦發生下面四種情況之一,就會導致死鎖的發生。

相互排斥: 一個線程或者進程永遠占有一共享資源,例如,獨占該資源。

循環等待: 進程A等待進程B,而後者又在等待進程C,而進程C又在等待進程A。

部分分配: 資源被部分分配。例如,進程A和B都需要用訪問一個文件,並且都要用到打印機,進程A獲得了文件資源,進程B獲得了打印機資源,但是兩個進程不能獲得全部的資源。

缺少優先權: 一個進程訪問了某個資源,但是一直不釋放該資源,即使該進程處于阻塞狀態。

假如上面四種情形都不出現,系統就不會發生死鎖。請再看一下剛才的文件/打印機的例子,當其中一個進程判定出它得不到它所需要的第二個資源,就釋放已經得到的第一個資源,那麽第二個教程可以獲得兩個資源,並能夠運行下去。

線程的高級用法

到目前爲止,我們已經談到創建和治理線程的基本知識。你需要做的就是啓動一個線程,並讓它運行。你的應用程序也許希望等待一個線程執行完畢,也許打算發送一個信息給線程,或者只打算讓線程在處理之前休眠一會兒。線程類提供了四種對線程進行操作的API調用。

Join

假如一個應用程序需要執行很多時間,比如一個耗時很長的計算工作,你可以把該計算工作設計成線程。但是,假定還有另外一個線程需要計算結果,當計算結果出來後,如何讓那個線程知道計算結果呢?解決該問題的一個方法是讓第二個線程一直不停地檢查一些變量的狀態,直到這些變量的狀態發生改變。這樣的方式在UNIX風格的服務器中經常用到。Java提供了一個更加簡單的機制,即線程類中的join 方法。

join 方法使得一個線程等待另外一個線程的結束。例如,一個GUI (或者其他線程)使用join方法等待一個子線程執行完畢:

CompleteCalcThread t = new

CompleteCalcThread();

t.start();

//

// 做一會兒其他的事情

// 然後等待

t.join();

// 使用計算結果...

你可以看到,用對子線程使用join方法,等待子線程執行完畢。 Join 有三種格式:

void join(): 等待線程執行完畢。

void join(long timeout): 最多等待某段時間讓線程完成。

void join(long milliseconds, int nanoseconds): 最多等待某段時間(毫秒+納秒),讓線程完成。

線程API isAlive同join相關聯時,是很有用的。一個線程在start(此時run方法已經啓動)之後,在stop之前的某時刻處于isAlive 狀態。

對于編寫線程的程序員來說,還有其他兩個有用的線程API,即wait和 notify。使用這兩個API,我們可以精確地控制線程的執行過程。考慮一個簡單的例子,有個生産者線程和消費者線程,爲了讓應用程序更有效率,所以我們不打算采用查詢等待的方法。當消費者可以消費對象時,消費者需要得知該信息。

我們可以把該例子闡述如下:生産者線程不斷地在運行著,把項目放入列表中,該列表的add方法由synchronize 要害字保護著,當一個對象添加到列表中,生産者就可以通知消費者:它已經添加一個對象,消費者可以消費該對象了。

 
特别声明:以上内容(如有图片或视频亦包括在内)为网络用户发布,本站仅提供信息存储服务。
 
  Al Saganich / 翻譯:朱英 <--在線程基礎的第二部分中,我們將了解一下使用Java線程的缺陷和副作用,以及在SUN JDK 1.2中是如何修改線程的運行機制的--> 在上篇文章《Java 101之線程基礎》中,我們介紹了線程的概念以及如何使用線程。這個月,我們將轉到更高級的話題,包括線程的缺陷及副作用,以及在SUN JDK 1.2中,是如何改進線程的運行機制的。 synchronize(同步) 讓我們回憶一下上篇文章中講的:線程答應兩個或者更多個進程同時執行。實際上,這些線程也可以共享對象和數據,在這種情形下,你要知道不同的線程在同一時間內不能存取同一數據,因爲一開始設計Java的時候,就采用了線程的概念,Java語言定義了一個非凡的要害字synchronize(同步),該要害字可以應用到代碼塊上,代碼塊也包括入口方法,該要害字的目的是防止多個線程在同一時間執行同一代碼塊內的代碼。 定義一個同步的方法,格式如下: [publicprivate] synchronized {type} methodname(...) 一個把同步這個要害字應用到方法中的簡單的例子: public class someClass { public void aMethod() { // Some code synchronized(this) { // Synchronized code block } // more code. } } 同步化的要害字可以保證在同一時間內只有一個線程可以執行該代碼段,而任何其他要用到該段代碼的線程將被阻塞,直到第一個線程執行完該段代碼。 死鎖和饑餓 對于饑餓的定義-由于別的並發的激活的過程持久占有所需資源,是莫個異步過程載客猜測的時間內不能被激活。 最常碰到的線程的兩個缺陷是死鎖和饑餓。當一個或者多個進程,在一個給定的任務中,協同作用,互相幹涉,而導致一個或者更多進程永遠等待下去,死鎖就發生了。與此類似,它當一個進程永久性地占有資源,使得其他進程得不到該資源,就發生了饑餓。 首先我們看一下死鎖問題。考慮一個簡單的例子,假如你到ATM機上取錢,但是你卻看到如下的信息「現在有沒有現金,請等會兒再試。」你需要錢,所以你就等了一會兒再試,但是你又看到同樣的信息。與此同時,在你後面,一輛運款裝甲車正等待著把錢放進ATM中,但是運款裝甲車到不了ATM取款機,因爲你的汽車擋著道。而你又要取到錢,才會離開原地。這種情況下,就發生了死鎖。 在饑餓的情形下,系統不處于死鎖狀態中,因爲有一個進程仍在處理之中,只是其他進程永遠得不到執行的機會。在什麽樣的環境下,會導致饑餓的發生,沒有預先確定好的規則。而一旦發生下面四種情況之一,就會導致死鎖的發生。 相互排斥: 一個線程或者進程永遠占有一共享資源,例如,獨占該資源。 循環等待: 進程A等待進程B,而後者又在等待進程C,而進程C又在等待進程A。 部分分配: 資源被部分分配。例如,進程A和B都需要用訪問一個文件,並且都要用到打印機,進程A獲得了文件資源,進程B獲得了打印機資源,但是兩個進程不能獲得全部的資源。 缺少優先權: 一個進程訪問了某個資源,但是一直不釋放該資源,即使該進程處于阻塞狀態。 假如上面四種情形都不出現,系統就不會發生死鎖。請再看一下剛才的文件/打印機的例子,當其中一個進程判定出它得不到它所需要的第二個資源,就釋放已經得到的第一個資源,那麽第二個教程可以獲得兩個資源,並能夠運行下去。 線程的高級用法 到目前爲止,我們已經談到創建和治理線程的基本知識。你需要做的就是啓動一個線程,並讓它運行。你的應用程序也許希望等待一個線程執行完畢,也許打算發送一個信息給線程,或者只打算讓線程在處理之前休眠一會兒。線程類提供了四種對線程進行操作的API調用。 Join 假如一個應用程序需要執行很多時間,比如一個耗時很長的計算工作,你可以把該計算工作設計成線程。但是,假定還有另外一個線程需要計算結果,當計算結果出來後,如何讓那個線程知道計算結果呢?解決該問題的一個方法是讓第二個線程一直不停地檢查一些變量的狀態,直到這些變量的狀態發生改變。這樣的方式在UNIX風格的服務器中經常用到。Java提供了一個更加簡單的機制,即線程類中的join 方法。 join 方法使得一個線程等待另外一個線程的結束。例如,一個GUI (或者其他線程)使用join方法等待一個子線程執行完畢: CompleteCalcThread t = new CompleteCalcThread(); t.start(); // // 做一會兒其他的事情 // 然後等待 t.join(); // 使用計算結果... 你可以看到,用對子線程使用join方法,等待子線程執行完畢。 Join 有三種格式: void join(): 等待線程執行完畢。 void join(long timeout): 最多等待某段時間讓線程完成。 void join(long milliseconds, int nanoseconds): 最多等待某段時間(毫秒+納秒),讓線程完成。 線程API isAlive同join相關聯時,是很有用的。一個線程在start(此時run方法已經啓動)之後,在stop之前的某時刻處于isAlive 狀態。 對于編寫線程的程序員來說,還有其他兩個有用的線程API,即wait和 notify。使用這兩個API,我們可以精確地控制線程的執行過程。考慮一個簡單的例子,有個生産者線程和消費者線程,爲了讓應用程序更有效率,所以我們不打算采用查詢等待的方法。當消費者可以消費對象時,消費者需要得知該信息。 我們可以把該例子闡述如下:生産者線程不斷地在運行著,把項目放入列表中,該列表的add方法由synchronize 要害字保護著,當一個對象添加到列表中,生産者就可以通知消費者:它已經添加一個對象,消費者可以消費該對象了。
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 
 熱帖排行
 
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有