編寫高效的執行緒安全類
編寫高效的執行緒安全類[@more@] Java 程式語言為編寫多執行緒應用程式提供強大的語言支援。但是,編寫有用的、沒有錯誤的多執行緒程式仍然比較困難。本文試圖概述幾種方法,程式設計師可用這幾種方法來建立高效的執行緒安全類。
併發性
只有當要解決的問題需要一定程度的併發性時,程式設計師才會從多執行緒應用程式中受益。例如,如果列印佇列應用程式僅支援一臺印表機和一臺客戶機,則不應該將它編寫為多執行緒的。一般說來,包含併發性的編碼問題通常都包含一些可以併發執行的操作,同時也包含一些不可併發執行的操作。例如,為多個客戶機和一個印表機提供服務的列印佇列可以支援對列印的併發請求,但向印表機的輸出必須是序列形式的。多執行緒實現還可以改善互動式應用程式的響應時間。
Synchronized 關鍵字
雖然多執行緒應用程式中的大多數操作都可以並行進行,但也有某些操作(如更新全域性標誌或處理共享檔案)不能並行進行。在這些情況下,必須獲得一個鎖來防止其他執行緒在執行此操作的執行緒完成之前訪問同一個方法。在 Java 程式中,這個鎖是透過 synchronized 關鍵字提供的。清單 1 說明了它的用法。
清單 1. 使用 synchronized 關鍵字來獲取鎖
public class MaxScore {
int max;
public MaxScore() {
max = 0;
}
public synchronized void currentScore(int s) {
if(s> max) {
max = s;
}
}
public int max() {
return max;
}
}
這裡,兩個執行緒不能同時呼叫 currentScore() 方法;當一個執行緒工作時,另一個執行緒必須阻塞。但是,可以有任意數量的執行緒同時透過 max() 方法訪問最大值,因為 max() 不是同步方法,因此它與鎖定無關。
試考慮在 MaxScore 類中新增另一個方法的影響,該方法的實現如清單 2 所示。
清單 2. 新增另一個方法
public synchronized void reset() {
max = 0;
}
這個方法(當被訪問時)不僅將阻塞 reset() 方法的其他呼叫,而且也將阻塞 MaxScore 類的同一個例項中的 currentScore() 方法,因為這兩個方法都訪問同一個鎖。如果兩個方法必須不彼此阻塞,則程式設計師必須在更低的級別使用同步。清單 3 是另一種情況,其中兩個同步的方法可能需要彼此獨立。
清單 3. 兩個獨立的同步方法
import java.util.*;
public class Jury {
Vector members;
Vector alternates;
public Jury() {
members = new Vector(12, 1);
alternates = new Vector(12, 1);
}
public synchronized void addMember(String name) {
members.add(name);
}
public synchronized void addAlt(String name) {
alternates.add(name);
}
public synchronized Vector all() {
Vector retval = new Vector(members);
retval.addAll(alternates);
return retval;
}
}
此處,兩個不同的執行緒可以將 members 和 alternates 新增到 Jury 物件中。請記住,synchronized 關鍵字既可用於方法,更一般地,也可用於任何程式碼塊。清單 4 中的兩段程式碼是等效的。
清單 4. 等效的程式碼
synchronized void f() {
void f() {
// 執行某些操作
synchronized(this) {
}
// 執行某些操作
}
}
所以,為了確保 addMember() 和 addAlt() 方法不彼此阻塞,可按清單 5 所示重寫 Jury 類。
清單 5. 重寫後的 Jury 類
import java.util.*;
public class Jury {
Vector members;
Vector alternates;
public Jury() {
members = new Vector(12, 1);
alternates = new Vector(12, 1);
}
public void addMember(String name) {
synchronized(members) {
members.add(name);
}
}
public void addAlt(String name) {
synchronized(alternates) {
alternates.add(name);
}
}
public Vector all() {
Vector retval;
synchronized(members) {
retval = new Vector(members);
}
synchronized(alternates) {
retval.addAll(alternates);
}
return retval;
}
}
請注意,我們還必須修改 all() 方法,因為對 Jury 物件同步已沒有意義。在改寫後的版本中,addMember()、addAlt() 和 all() 方法只訪問與 members 和 alternates 物件相關的鎖,因此鎖定 Jury 物件毫無用處。另請注意,all() 方法本來可以寫為清單 6 所示的形式。
清單 6. 將 members 和 alternates 用作同步的物件
public Vector all() {
synchronized(members) {
synchronized(alternates) {
Vector retval;
retval = new Vector(members);
retval.addAll(alternates);
}
}
return retval;
}
但是,因為我們早在需要之前就獲得 members 和 alternates 的鎖,所以這效率不高。清單 5 中的改寫形式是一個較好的示例,因為它只在最短的時間內持有鎖,並且每次只獲得一個鎖。這樣就完全避免了當以後增加程式碼時可能產生的潛在死鎖問題。
併發性
只有當要解決的問題需要一定程度的併發性時,程式設計師才會從多執行緒應用程式中受益。例如,如果列印佇列應用程式僅支援一臺印表機和一臺客戶機,則不應該將它編寫為多執行緒的。一般說來,包含併發性的編碼問題通常都包含一些可以併發執行的操作,同時也包含一些不可併發執行的操作。例如,為多個客戶機和一個印表機提供服務的列印佇列可以支援對列印的併發請求,但向印表機的輸出必須是序列形式的。多執行緒實現還可以改善互動式應用程式的響應時間。
Synchronized 關鍵字
雖然多執行緒應用程式中的大多數操作都可以並行進行,但也有某些操作(如更新全域性標誌或處理共享檔案)不能並行進行。在這些情況下,必須獲得一個鎖來防止其他執行緒在執行此操作的執行緒完成之前訪問同一個方法。在 Java 程式中,這個鎖是透過 synchronized 關鍵字提供的。清單 1 說明了它的用法。
清單 1. 使用 synchronized 關鍵字來獲取鎖
public class MaxScore {
int max;
public MaxScore() {
max = 0;
}
public synchronized void currentScore(int s) {
if(s> max) {
max = s;
}
}
public int max() {
return max;
}
}
這裡,兩個執行緒不能同時呼叫 currentScore() 方法;當一個執行緒工作時,另一個執行緒必須阻塞。但是,可以有任意數量的執行緒同時透過 max() 方法訪問最大值,因為 max() 不是同步方法,因此它與鎖定無關。
試考慮在 MaxScore 類中新增另一個方法的影響,該方法的實現如清單 2 所示。
清單 2. 新增另一個方法
public synchronized void reset() {
max = 0;
}
這個方法(當被訪問時)不僅將阻塞 reset() 方法的其他呼叫,而且也將阻塞 MaxScore 類的同一個例項中的 currentScore() 方法,因為這兩個方法都訪問同一個鎖。如果兩個方法必須不彼此阻塞,則程式設計師必須在更低的級別使用同步。清單 3 是另一種情況,其中兩個同步的方法可能需要彼此獨立。
清單 3. 兩個獨立的同步方法
import java.util.*;
public class Jury {
Vector members;
Vector alternates;
public Jury() {
members = new Vector(12, 1);
alternates = new Vector(12, 1);
}
public synchronized void addMember(String name) {
members.add(name);
}
public synchronized void addAlt(String name) {
alternates.add(name);
}
public synchronized Vector all() {
Vector retval = new Vector(members);
retval.addAll(alternates);
return retval;
}
}
此處,兩個不同的執行緒可以將 members 和 alternates 新增到 Jury 物件中。請記住,synchronized 關鍵字既可用於方法,更一般地,也可用於任何程式碼塊。清單 4 中的兩段程式碼是等效的。
清單 4. 等效的程式碼
synchronized void f() {
void f() {
// 執行某些操作
synchronized(this) {
}
// 執行某些操作
}
}
所以,為了確保 addMember() 和 addAlt() 方法不彼此阻塞,可按清單 5 所示重寫 Jury 類。
清單 5. 重寫後的 Jury 類
import java.util.*;
public class Jury {
Vector members;
Vector alternates;
public Jury() {
members = new Vector(12, 1);
alternates = new Vector(12, 1);
}
public void addMember(String name) {
synchronized(members) {
members.add(name);
}
}
public void addAlt(String name) {
synchronized(alternates) {
alternates.add(name);
}
}
public Vector all() {
Vector retval;
synchronized(members) {
retval = new Vector(members);
}
synchronized(alternates) {
retval.addAll(alternates);
}
return retval;
}
}
請注意,我們還必須修改 all() 方法,因為對 Jury 物件同步已沒有意義。在改寫後的版本中,addMember()、addAlt() 和 all() 方法只訪問與 members 和 alternates 物件相關的鎖,因此鎖定 Jury 物件毫無用處。另請注意,all() 方法本來可以寫為清單 6 所示的形式。
清單 6. 將 members 和 alternates 用作同步的物件
public Vector all() {
synchronized(members) {
synchronized(alternates) {
Vector retval;
retval = new Vector(members);
retval.addAll(alternates);
}
}
return retval;
}
但是,因為我們早在需要之前就獲得 members 和 alternates 的鎖,所以這效率不高。清單 5 中的改寫形式是一個較好的示例,因為它只在最短的時間內持有鎖,並且每次只獲得一個鎖。這樣就完全避免了當以後增加程式碼時可能產生的潛在死鎖問題。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10901326/viewspace-965635/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 編寫執行緒安全的JSP應用程式執行緒JS
- 什麼時候執行緒不安全?怎樣做到執行緒安全?怎麼擴充套件執行緒安全的類?執行緒套件
- Java併發-執行緒安全的集合類Java執行緒
- 【連載 12】執行緒安全的集合類執行緒
- Java執行緒安全的集合類:Map、List、SetJava執行緒
- 【Java多執行緒】執行緒安全的集合Java執行緒
- 從原始碼分析ConcurrentHashMap執行緒安全和高效的特性原始碼HashMap執行緒
- java安全編碼指南之:執行緒安全規則Java執行緒
- 執行緒安全執行緒
- 多執行緒系列之 執行緒安全執行緒
- iOS 多執行緒之執行緒安全iOS執行緒
- Java執行緒(一):執行緒安全與不安全Java執行緒
- 認識執行緒、建立執行緒寫法執行緒
- 【多執行緒總結(二)-執行緒安全與執行緒同步】執行緒
- 造成類在多執行緒時不安全的原因執行緒
- 什麼是執行緒安全和執行緒不安全執行緒
- Java執行緒(九):Condition-執行緒通訊更高效的方式Java執行緒
- 執行緒安全(二)執行緒
- Java執行緒安全Java執行緒
- VC編寫多執行緒sql盲注工具.doc執行緒SQL
- 編碼:執行緒執行監控執行緒
- iOS多執行緒安全-13種執行緒鎖?iOS執行緒
- Java 多執行緒基礎(四)執行緒安全Java執行緒
- 多執行緒,你覺得你安全了?(執行緒安全問題)執行緒
- 使用Python編寫一個多執行緒的12306搶票程式Python執行緒
- 併發程式設計之多執行緒執行緒安全程式設計執行緒
- 多執行緒與高併發(二)執行緒安全執行緒
- 小度分享-【多執行緒工作及執行緒安全】執行緒
- iOS開發基礎——執行緒安全(執行緒鎖)iOS執行緒
- 併發與多執行緒之執行緒安全篇執行緒
- ArrayList 的執行緒安全問題執行緒
- 保障執行緒安全的設計執行緒
- Concurrency(四:執行緒安全)執行緒
- 執行緒安全性執行緒
- 容器不是執行緒安全執行緒
- ConcurrentHashMap執行緒安全嗎?HashMap執行緒
- 【從0開始編寫webserver·基礎篇#01】為什麼需要執行緒池?寫一個執行緒池吧WebServer執行緒
- [短文速讀 -5] 多執行緒程式設計引子:程式、執行緒、執行緒安全執行緒程式設計
- Java多執行緒中執行緒安全與鎖問題Java執行緒