關于解決 Java 編程語言線程問題的建議(3)

發表于:2007-07-14來源:作者:點擊數: 標簽:
修改 Thread 類 同時支持搶占式和協作式線程的能力在某些 服務器 應用程序中是基本要求,尤其是在想使系統達到最高 性能 的情況下。我認為 Java 編程語言在簡化線程模型上走得太遠了,并且 Java 編程語言應支持 Posix/Solaris 的“綠色(green)線程”和“輕便
修改 Thread 類

同時支持搶占式和協作式線程的能力在某些服務器應用程序中是基本要求,尤其是在想使系統達到最高性能的情況下。我認為
Java 編程語言在簡化線程模型上走得太遠了,并且 Java 編程語言應支持
Posix/Solaris 的“綠色(green)線程”和“輕便(lightweight)進程”概念(在“(Taming Java Threads”第一章中討論)。
這就是說,有些 Java 虛擬機的實現(例如在 NT 上的 Java 虛擬機)應在其內部仿真協作式進程,其它
Java 虛擬機應仿真搶占式線程。而且向 Java 虛擬機加入這些擴展是很容易的。



一個 Java 的 Thread 應始終是搶占式的。這就是說,一個 Java 編程語言的線程應像 Solaris
的輕便進程一樣工作。 Runnable 接口可以用于定義一個 Solaris 式的“綠色線程”,此線程必需能把控制權轉給運行
在相同輕便進程中的其它綠色線程。




例如,目前的語法:




class My_thread implements Runnable
{ public void run(){ /*...*/ }
}

new Thread( new My_thread );





能有效地為 Runnable 對象產生一個綠色線程,并把它綁定到由
Thread 對象代表的輕便進程中。這種實現對于現有代碼是透明的,因為它的有效性和現有的完全一樣。


把 Runnable 對象想成為綠色線程,使用這種方法,只需向
Thread 的構造函數傳遞幾個 Runnable對象,就可以擴展
Java 編程語言的現有語法,以支持在一個單一輕便線程有多個綠色線程。(綠色線程之間可以相互協作,但是它們可被運行在其它輕便進程
(Thread 對象) 上的綠色進程(Runnable 對象) 搶占。)。例如,下面的代碼會為每個
runnable 對象創建一個綠色線程,這些綠色線程會共享由 Thread 對象代表的輕便進程。


new Thread( new My_runnable_object(), new My_other_runnable_object() );





現有的覆蓋(override) Thread 對象并實現 run() 的習慣繼續有效,但是它應映射到一個被綁定到一輕便進程的綠色線程。(在
Thread() 類中的缺省 run() 方法會在內部有效地創建第二個 Runnable 對象。)

線程間的協作

應在語言中加入更多的功能以支持線程間的相互通信。目前,PipedInputStream
和 PipedOutputStream 類可用于這個目的。但是對于大多數應用程序,它們太弱了。我建議向
Thread 類加入下列函數:


增加一個 wait_for_start() 方法,它通常處于阻塞狀態,直到一個線程的
run() 方法啟動。(如果等待的線程在調用 run 之前被釋放,這沒有什么問題)。用這種方法,一個線程可以創建一個或多個輔助線程,并保證在創建線程繼續執行操作之前,這些輔助線程會處于運行狀態。


(向 Object 類)增加 $send (Object o) 和 Object=$receive()
方法,它們將使用一個內部阻斷隊列在線程之間傳送對象。阻斷隊列應作為第一個
$send() 調用的副產品被自動創建。 $send() 調用會把對象加入隊列。
$receive() 調用通常處于阻塞狀態,直到有一個對象被加入隊列,然后它返回此對象。這種方法中的變量應支持設定入隊和出隊的操作超時能力:
$send (Object o, long timeout)
和 $receive (long timeout)。



對于讀寫鎖的內部支持

讀寫鎖的概念應內置到 Java 編程語言中。讀寫器鎖在“Taming Java Threads”(和其它地方)中有詳細討論,概括地說:一個讀寫鎖支持多個線程同時訪問一個對象,但是在同一時刻只有一個線程可以修改此對象,并且在訪問進行時不能修改。讀寫鎖的語法可以借用 synchronized 關鍵字:

static Object global_resource;

//...

public void a()
{
$reading( global_resource )
{ // While in this block, other threads requesting read
// aclearcase/" target="_blank" >ccess to global_resource will get it, but threads
// requesting write access will block.
}
}

public void b()
{
$writing( global_resource )
{ // Blocks until all ongoing read or write operations on
// global_resource are complete. No read or write
// operation or global_resource can be initiated while
// within this block.
}
}

public $reading void c()
{ // just like $reading(this)...
}

public $writing void d()
{ // just like $writing(this)...
}





對于一個對象,應該只有在 $writing 塊中沒有線程時,才支持多個線程進入
$reading 塊。在進行讀操作時,一個試圖進入 $writing
塊的線程會被阻斷,直到讀線程退出 $reading
塊。 當有其它線程處于 $writing 塊時,試圖進入 $reading
或 $writing 塊的線程會被阻斷,直到此寫線程退出 $writing
塊。



如果讀和寫線程都在等待,缺省情況下,讀線程會首先進行。但是,可以使用
$writer_priority 屬性修改類的定義來改變這種缺省方式。如:



$write_priority class IO
{
$writing write( byte[] data )
{ //...
}

$reading byte[] read( )
{ //...
}
}


訪問部分創建的對象應是非法的

當前情況下,JLS 允許訪問部分創建的對象。例如,在一個構造函數中創建的線程可以訪問正被創建的對象,既使此對象沒有完全被創建。下面代碼的結果無法確定:


class Broken
{ private long x;

Broken()
{ new Thread()
{ public void run()
{ x = -1;
}
}.start();

x = 0;
}
}




設置 x 為 -1 的線程可以和設置 x 為 0 的線程同時進行。所以,此時 x 的值無法預測。


對此問題的一個解決方法是,在構造函數沒有返回之前,對于在此構造函數中創建的線程,既使它的優先級比調用
new 的線程高,也要禁止運行它的 run() 方法。




這就是說,在構造函數返回之前, start()
請求必須被推遲。

另外,Java 編程語言應可允許構造函數的同步。換句話說,下面的代碼(在當前情況下是非法的)會象預期的那樣工作:

class Illegal
{ private long x;

synchronized Broken()
{ new Thread()
{ public void run()
{ synchronized( Illegal.this )
{
x = -1;
}
}
}.start();

x = 0;
}
}






我認為第一種方法比第二種更簡潔,但實現起來更為困難。


volatile
關鍵字應象預期的那樣工作

JLS 要求保留對于 volatile 操作的請求。大多數 Java 虛擬機都簡單地忽略了這部分內容,這是不應該的。在多處理器的情況下,許多主機都出現了這種問題,但是它本應由
JLS 加以解決的。如果您對這方面感興趣,馬里蘭大學的 Bill Pugh
正在致力于這項工作(請參閱參考資料)。

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97