Java 線程缺陷和副作用的解決辦法(2)
表A: 演示高級線程方法的偽代碼 class ProdCons { class List { public synchronized boolean add(Object o) {...} public synchronized boleanremove (Object o) {...} } List data = new List(); ProdThread producer = null; ConsThread consumer = null;
表A: 演示高級線程方法的偽代碼
class ProdCons {
class List {
public synchronized boolean add(Object o)
{...}
public synchronized boleanremove (Object o)
{...}
}
List data = new List();
ProdThread producer = null;
ConsThread consumer = null;
ProdCons() {
producer = new ProdThread(this);
consumer = new ConsThread(this);
producer.start();
consumer.start();
}
}
消費者和生產者的類,請見表B和表C。
表B: Class ConsThread
class ConsThread extends Thread {
ProdCons parent;
ConsThread(ProdCons parent) {
this.parent = parent;
}
public synchronized void canConsume() {
notify();
}
public void run() {
boolean consumed;
do {
synchronized(this) {
try { wait();}
catch (Exception e) { ; }
}
do {
String str = (String)parent.list.remove();
if ( null == str) {
consumed = false;
break;
}
consumed = true;
System.out.println("Consumer
=>consumed " + str);
}
while ( true );
}
while (consumed);
}
}
表C: Class ProdThread
class ProdThread extends Thread {
ProdCons parent;
ProdThread(ProdCons parent) {
this.parent = parent;
}
public void run() {
for ( int i = 0; i < 10; i++) {
String str = new String("ImAString" + i);
System.out.println("Producer produced " + str);
parent.list.add(str);
parent.consumer.canConsume();
}
parent.consumer.canConsume();
}
}
注意:notify和wait兩個API都必須位于同步化(synchronized)的方法中或者代碼塊中!
線程和Sun JDK 1.2
線程提供了一項很有價值的服務,極大地增強了Java程序設計語言的功能。然而,目前的線程實現的確存在一些問題。這些問題的存在,使得Sun JDK 1.2中線程的stop, suspend和resume方法導致人們的批評。
如果我們回到上面的生產者/消費者例子,我們就可以更好地理解這個問題。首先,我們看看死鎖。當運行一個applet小程序時,在通常的情況下,兩個線程運行時,相安無事,但是,但用戶點擊到另外一個網頁時,問題出現了。如果生產者正在添加一個項目到列表中,最壞的情況就是消費者線程被阻塞。假定,小程序正在創建一個對象,此時突然被掛起(suspended),其他的小程序就不能再對該數據進行更新。盡管出現這樣的機會不多,它們的確存在,有時會引起問題。
線程的第二個問題有關不一致的問題。再來看一下生產者/消費者的例子,不難想象,如果生產者線程在添加項目的過程中遇到被中止的情況,可能會造成列表狀態不一致。如果我們全面檢查現有的Java小程序的個數,就不難發現問題所在。
處理這個不一致的問題的最簡單的方法就是派生一個新的線程類,該線程類具有如下功能:通過一個方法的調用可以改變其狀態。表D就定義了這樣的一個類。MyThread類可以被掛起和重新執行,而無需擔心MyThread類的資源會崩潰。MyThread類中的方法 changeState用于暗示應該暫停,停止或者重新執行線程,而不同于以往的停止或者暫停線程??梢韵蚓€程發出請求,要求線程在合適的時候處理該請求,而不是強制處理該請求,因而無需向線程發出停止命令。
表D: Class MyThread
public class MyThread extends Thread {
//States the thread can be in.
static final int STATE_RUNNING = 0;
static final int STATE_STOP = 1;
static final int STATE_SUSPEND = 2;
private int currentState = STATE_RUNNING;
// The public method changeState allows
// another process to poke at that hread
// and tell it to do something when it
// next gets a chance.
public final synchronized void
changeState(int newState) {
currentState = newState;
if (STATE_RUNNING == currentState)
notify();
// Must have been suspended.
}
private synchronized boolean currentState() {
// If we where asked to suspend,
// just hang out until we are
// asked to either run or stop.
while ( STATE_SUSPEND == currentState) {
try{ wait(); }
catch (Exception e) {};
}
if ( STATE_STOP == currentState )
return false;
else
return true;
}
public void run() {
do {
if (currentState() == false)
return; // Done
// Perform some work
} while (true);
}
}
MyThread類的用戶可以重載run方法,然而,用戶需要檢查是否有另外的類請求線程改變狀態。在JDK 1.2 中對線程的運行機制所做的改變,是問題的癥結所在,線程在運行時是否出現不一致,在線程關閉后,是否放棄所占用的資源,線程的運行是否正常,這些工作都是要開發者自己來確保完成了。
結論
線程功能強大而使用復雜。每位Java開發者可以在很多應用場合用到線程。本文中,我們檢查了線程的一些副作用,以及線程的一些高級用法。隨著Sun JDK 1.2的推出,開發者們將被迫對其編寫的線程對系統和其他進程的作用過程考慮得更加周到。最終,對于線程及其相關知識的正確理解,將會有助于聰明的開發者設計出更加健壯的應用程序。
|
原文轉自:http://www.anti-gravitydesign.com
- 評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
-
国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97
|