什麼是線程? 線程的概念並不難於掌握
它是程序代碼的一個獨立的執行通道
當多個線程執行時
經由相同代碼的一個線程的通道通常與其它的不同
例如
假設一個線程執行一段相當於一個if
else語句的if部分的字節代碼時
而另一個線程正執行相當於else部分的字節代碼
JVM怎樣保持對於每一個線程執行的跟蹤呢?JVM給每一個線程它自己的方法調用堆棧
另外跟蹤當前指令字節代碼
方法堆棧跟蹤本地變量
JVM傳遞給一個方法的參數
以及方法的返回值
當多個線程在同一個程序中執行字節代碼序列時
這種行為叫作多線程
多線程在多方面有利於程序
·當執行其它任務時多線程GUI(圖形用戶界面)程序仍能保持對用戶的響應
比如重編頁碼或打印一個文檔
·帶線程的程序一般比它們沒有帶線程的副本程序完成得快
這尤其表現在線程運行在一個多處理器機器上
在這裡每一個線程都有它自己的處理器
Java通過java
lang
Thread類完成多線程
每一個線程對象描述一個單獨的執行線程
那些運行發生在線程的run()方法中
因為缺省的run()方法什麼都不做
你必須創建Thread子類並重載run()以完成有用的工作
練習列表
中領略一個在Thread中的線程及多線程
列表
ThreadDemo
java
// ThreadDemo
java
class ThreadDemo
{
public static void main (String [] args)
{
MyThread mt = new MyThread ();
mt
start ();
for (int i =
; i <
; i++)
System
out
println (
i =
+ i +
i * i =
+ i * i);
}
}
class MyThread extends Thread
{
public void run ()
{
for (int count =
row =
; row <
; row++
count++)
{
for (int i =
; i < count; i++)
System
out
print (
*
);
System
out
print (
\n
);
}
}
}
列表
顯示了一個由類ThreadDemo和MyThread組成的應用程序的源代碼
類ThreadDemo通過創建一個MyThread對象驅動應用程序
開始一個與其對象相關的線程並執行一段打印一個正方形表的代碼
相反
MyThread重載Thread的run()方法打印(通過標准輸入流)一個由星形符號組成的直角三角形
當你鍵入java ThreadDemo運行應用程序時
JVM創建一個運行main()方法的開始線程
通過執行mt
start ()
開始線程告訴JVM創建一個執行包含MyThread對象的run()方法的字節代碼指令的第二個線程
當start()方法返回時
開始線程循環執行打印一個正方形表
此時另一個新線程執行run()方法打印直角三角形
輸出會象什麼樣呢?運行ThreadDemo就可以看到
你將注意到每一個線程的輸出與其它線程的輸出相互交替
這樣的結果是因為兩個線程將它們的輸出都發送到了同樣的標准輸出流
注意
多數(不是所有)JVM設備使用下層平台的線程性能
因為那些性能是平台特有的
你的多線程程序的輸出順序可能與一些人的其他輸出的順序不一樣
這種不同是由於時序的安排
我將在這一系列的稍後探討這一話題
線程類
要精通寫多線程代碼
你必須首先理解創建Thread類的多種方法
這部份將探討這些方法
明確地說
你將學到開始線程的方法
命名線程
使線程休眠
決定一個線程是否激活
將一個線程與另一個線程相聯
和在當前線程的線程組及子組中列舉所有激活的線程
我也會討論線程調試輔助程序及用戶線程與監督線程的對比
我將在以後的文章中介紹線程方法的余下部份
Sun不贊成的方法除外
警告
Sun有一些不贊成的線程方法種類
比如suspend()和resume()
因為它們能鎖住你的程序或破壞對象
所以
你不必在你的代碼中調用它們
考慮到針對這些方法工作區的SDK文件
在這篇文章中我沒有包含這些方法
構造線程
Thread有八個構造器
最簡單的是
·Thread()
用缺省名稱創建一個Thread對象
·Thread(String name)
用指定的name參數的名稱創建一個Thread對象
下一個最簡單的構造器是Thread(Runnable target)和Thread(Runnable target
String name)
除Runnable參數之外
這些構造器與前述的構造器一樣
不同的是
Runnable參數識別提供run()方法的線程之外的對象
(你將在這篇文章稍後學到Runnable
)最後幾個構造器是Thread(String name)
Thread(Runnable target)
和Thread(Runnable target
String name)
然而
最後的構造器包含了一個為了組織意圖的ThreadGroup參數
最後四個構造器之一
Thread(ThreadGroup group
Runnable target
String name
long stackSize)
令人感興趣的是它能夠讓你指定想要的線程方法調用堆棧的大小
能夠指定大小將證明在使用遞歸方法(一種為何一個方法不斷重復調用自身的技術)優美地解決一些問題的程序中是十分有幫助的
通過明確地設置堆棧大小
你有時能夠預防StackOverflowErrors
然而
太大將導致OutOfMemoryErrors
同樣
Sun將方法調用堆棧的大小看作平台依賴
依賴平台
方法調用堆棧的大小可能改變
因此
在寫調用Thread(ThreadGroup group
Runnable target
String name
long stackSize)代碼前仔細考慮你的程序分枝
開始你的運載工具
線程類似於運載工具
它們將程序從開始移動到結束
Thread 和Thread子類對象不是線程
它們描述一個線程的屬性
比如名稱和包含線程執行的代碼(經由一個run()方法)
當一個新線程執行run()時
另一個線程正調用Thread或其子類對象的start()方法
例如
要開始第二個線程
應用程序的開始線程—它執行main()—調用start()
作為響應
JVM和平台一起工作的線程操作代碼確保線程正確地初始化並調用Thread或其子類對象的run()方法
一旦start()完成
多重線程便運行
因為我們趨向於在一種線性的方式中思維
我們常發現當兩個或更多線程正運行時理解並發(同時)行為是困難的
因此
你應該看看顯示與時間對比一個線程正在哪裡執行(它的位置)的圖表
下圖就是這樣一個圖表
與時間對比一個開始線程和一個新建線程執行位置的行為
圖表顯示了幾個重要的時間段
·開始線程的初始化
·線程開始執行main()瞬間
·線程開始執行start()的瞬間
·start()創建一個新線程並返回main()的瞬間
·新線程的初始化
·新線程開始執行run()的瞬間
·每個線程結束的不同瞬間
注意新線程的初始化
它對run()的執行
和它的結束都與開始線程的執行同時發生
警告
一個線程調用start()後
在run()方法退出前並發調用那方法將導致start()擲出一個java
lang
IllegalThreadStateException對象
怎樣使用名稱 在一個調試會話期間
使用用戶友好方式從另一個線程區別其中一個線程證明是有幫助的
要區分其中一個線程
Java給一個線程取一個名稱
Thread缺省的名稱是一個短線連字符和一個零開始的數字符號
你可以接受Java的缺省線程名稱或選擇使用你自己的
為了能夠自定義名稱
Thread提供帶有name參數和一個setName(String name)方法的構造器
Thread也提供一個getName()方法返回當前名稱
表
顯示了怎樣通過Thread(String name)創建一個自定義名稱和通過在run()方法中調用getName()檢索當前名稱
表
NameThatThread
java
// NameThatThread
java
class NameThatThread
{
public static void main (String [] args)
{
MyThread mt;
if (args
length ==
)
mt = new MyThread ();
else
mt = new MyThread (args [
]);
mt
start ();
}
}
class MyThread extends Thread
{
MyThread ()
{
//編譯器創建等價於super()的字節代碼
}
MyThread (String name)
{
super (name); //將名稱傳遞給Thread超類
}
public void run ()
{
System
out
println (
My name is:
+ getName ());
}
}
你能夠在命令行向MyThread傳遞一個可選的name參數
例如
java NameThatThread X 建立X作為線程的名稱
如果你指定一個名稱失敗
你將看到下面的輸出
My name is: Thread
如果你喜歡
你能夠在MyThread(String name)構造器中將super(name)調用改變成setName(String name)調用——作為setName(name)後一種方法調用達到同樣建立線程名稱的目的——作為super(name)我作為練習保留給你們
注意
Java主要將名稱指派給運行main() 方法的線程
開始線程
你特別要看看當開始線程擲出一個例外對象時在線程
main
的例外顯示的JVM的缺省例外處理打印消息
休眠或停止休眠
在這一欄後面
我將向你介紹動畫——在一個表面上重復畫圖形
這稍微不同於完成一個運動畫面
要完成動畫
一個線程必須在它顯示兩個連續畫面時中止
調用Thread的靜態sleep(long millis)方法強迫一個線程中止millis毫秒
另一個線程可能中斷正在休眠的線程
如果這種事發生
正在休眠的線程將醒來並從sleep(long millis)方法擲出一個InterruptedException對象
結果
調用sleep(long millis)的代碼必須在一個try代碼塊中出現——或代碼方法必須在自己的throws子句中包括InterruptedException
為了示范sleep(long millis)
我寫了一個CalcPI
應用程序
這個應用
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27647.html