?? 7.html
字號:
<HTML><HEAD><TITLE>黃金書屋</TITLE><META content="text/html; charset=gb2312" http-equiv=Content-Type><link rel="stylesheet" href="/cssset.css"></HEAD><BODY bgColor=#ffffff leftMargin=0 link=#000000 topMargin=0 vLink=#000000><center> <script language="JavaScript" src="/top.js"></script></center><TABLE background=images/bj.jpg border=0 cellSpacing=0 width="100%"> <TR> <TD bgColor=#c6bba4 vAlign=top width="12%"></TD> <TD background=/images/bj.jpg vAlign=top width="76%"> <center> <iframe width=468 height=60 marginwidth=0 marginheight=0 hspace=0 vspace=0 frameborder=0 scrolling=no bordercolor="#000000" src="/banner3.html"></iframe> </center> <br> </TD> <TD bgColor=#c6bba4 vAlign=top width="12%"></TD> </TR></TABLE><TABLE background=images/bj.jpg border=0 cellSpacing=0 width="100%"> <TR> <TD bgColor=#c6bba4 vAlign=top width="11%" align="right"> <br><br><br> <b><a href="/index.html">回首頁</a><br><br><a href='6.html'>上一頁</a><br><br><a href='8.html'>下一頁</a><br><br><a href='http://pub.goldnets.com:81/bbs/post.php?job=new&topic=12210' target=_blank> 我有話說 </a><br><br><a href='http://pub.goldnets.com:81/bbs/bbslist.php?topic=12210' target=_blank> 評論一覽 </a></center><br><!--title_end--></b> </TD> <TD bgColor=#c6bba4 vAlign=top width="1%"></TD> <TD background=/images/bj.jpg vAlign=top width="76%"> <br> <hr align="center" width="98%" size="1"> <br> <font color="blue">Java語言入門</font> >> <font color=red>第 七 章 多 線 程</font><hr width=90% color=#7A7A71><table width=88% border=0 align=center><tr><td><div style=font-size:12pt><pre> Java語言入門
第 七 章 多 線 程
7.1 多 線 程 的 概 念
多 線 程 編 程 的 含 義 是 你 可 將 程 序 任 務 分 成 幾 個 并 行 的
子 任 務。 特 別 是 在 網 絡 編 程 中, 你 會 發 現 很 多 功 能 是 可
以 并 發 執 行 的。 比 如 網 絡 傳 輸 速 度 較 慢, 用 戶 輸 入 速 度
較 慢, 你 可 以 用 兩 個 獨 立 的 線 程 去 完 成 這 ?copy; 功 能, 而
不 影 響 正 常 的 顯 示 或 其 他 功 能。 多 線 程 是 與 單 線 程 比 較
而 言 的, 普 通 的WINDOWS采 用 單 線 程 程 序 結 構, 其 工 作 原 理
是: 主 程 序 有 一 個 消 息 循 環, 不 斷 從 消 息 隊 列 中 讀 入 消
息 來 決 定 下 一 步 所 要 干 的 事 情, 一 般 是 一 個 子 函 數, 只
有 等 這 個 子 函 數 執 行 完 返 回 后, 主 程 序 才 能 接 收 另 外 的
消 息 來 執 行。 比 如 子 函 數 功 能 是 在 讀 一 個 網 絡 數 據, 或
讀 一 個 文 件, 只 有 等 讀 完 這 ?copy; 數 據 或 文 件 才 能 接 收
下 一 個 消 息。 在 執 行 這 個 子 函 數 過 程 中 你 什 么 也 不 能
干。 但 往 往 讀 網 絡 數 據 和 等 待 用 戶 輸 入 有 很 多 時 間 處 于
等 待 狀 態, 多 線 程 利 用 這 個 特 點 將 任 務 分 成 多 個 并 發 任
務 后, 就 可 以 解 決 這 個 問 題。
7.1.1 Java線 程 的 模 型
Java的 設 計 思 想 是 建 立 在 當 前 大 多 數 操 作 系 統 都 實 現
了 線 程 調 度。Java虛 擬 機 的 很 多 任 務 都 依 賴 線 程 調 度, 而
且 所 有 的 類 庫 都 是 為 多 線 程 設 計 的。 實 時 上,Java支 持
Macintosh和Ms-dos 的 平 臺 ?reg; 所 以 遲 遲 未 出 來 就 是 因 為 這
兩 個 平 臺 都 不 支 持 多 線 程。Java利 用 多 線 程 實 現 了 整 個
執 行 環 境 是 異 步 的。 在Java程 序 里 沒 有 主 消 息 循 環。 如 果
一 個 線 程 等 待 讀 取 網 絡 數 據, 它 可 以 運 行 但 不 停 止 系 統
的 其 他 線 程 執 行。 用 于 處 理 用 戶 輸 入 的 線 程 大 多 時 間 是
等 待 用 戶 敲 鍵 盤 或 擊 鼠 標。 你 還 可 以 使 動 畫 的 每 一
幀 ?reg; 間 停 頓 一 秒 而 并 不 使 系 統 暫 停。 一 ?copy; 線 程 啟
動 后, 它 可 以 被 掛 起, 暫 時 不 讓 它 執 行。 掛 起 的 線 程 可 以
重 新 恢 復 執 行。 任 何 時 間 線 程 都 可 以 被 停 止, 被 停 止 的
線 程 就 不 能 再 重 新 啟 動。 Java語 言 里, 線 程 表 現 為 線 程
類, 線 程 類 封 裝 了 所 有 需 要 的 線 程 操 作 控 制。 在 你 心 里,
必 須 很 清 晰 地 區 分 開 線 程 對 象 和 運 行 線 程, 你 可 以 將 線
程 對 象 看 作 是 運 行 線 程 的 控 制 面 板。 在 線 程 對 象 里 有 很
多 函 數 來 控 制 一 個 線 程 是 否 運 行, 睡 眠, 掛 起 或 停 止。 線
程 類 是 控 制 線 程 行 為 的 唯 一 的 手 段。 一 ?copy; 一 個Java程
序 啟 動 后, 就 已 經 有 一 個 線 程 在 運 行。 你 可 通 過 調 用
Thread.currentThread 函 數 來 查 看 當 前 運 行 的 是 哪 一 個 線 程。
一 ?copy; 你 得 到 一 個 線 程 的 控 制 柄, 你 就 可 以 作 一 ?copy;
很 有 趣 的 事 情, 即 使 單 線 程 也 一 樣。 下 面 這 個 例 子 讓 你
知 道 怎 樣 操 縱 當 前 線 程。 Filename:testthread
class testthread { public static void main(String args[]) { Thread t
=Thread.currentThread(); t.setName("This Thread is running");
System.out.println("The running thread:" + t); try { for (int i=0;i<5;i++)
{ System.out.println("Sleep time "+i); Thread.sleep(1000); }
} catch (InterruptedException e) {System.out.println("thread has
wrong"); }
} }
執 行 結 果:java testthread The running thread:Thread[This Thread is
running,5,main] Sleep time 0 Sleep time 1 Sleep time 2 Sleep time 3 Sleep
time 4
7.1.2 啟 動 接 口
一 個 線 程 并 不 激 動 人 心, 多 個 線 程 才 有 實 際 意 義。 我 們
怎 樣 創 建 更 多 的 線 程 呢? 我 們 需 要 創 建 線 程 類 的 另 一
個 實 例。 當 我 們 構 造 了 線 程 類 的 一 個 新 的 實 例, 我 們 必
須 告 訴 它 在 新 的 線 程 里 應 執 行 哪 一 段 程 序。 你 可 以 在 任
意 實 現 了 啟 動 接 口 的 對 象 上 啟 動 一 個 線 程。 啟 動 接 口 是
一 個 抽 象 接 口, 來 表 示 本 對 象 有 一 ?copy; 函 數 想 異 步 執
行。 要 實 現 啟 動 接 口, 一 個 類 只 需 要 有 一 個 叫run的 函 數。
下 面 是 創 建 一 個 新 線 程 的 例 子:
Filename:twothread.java
class twothread implements Runnable { twothread() { Thread t1
=Thread.currentThread(); t1.setName("The first main thread");
System.out.println("The running thread:" + t1); Thread t2 = new
Thread(this,"the second thread"); System.out.println("creat another
thread"); t2.start(); try { System.out.println("first thread will
sleep"); Thread.sleep(3000); }catch (InterruptedException e)
{System.out.println("first thread has wrong"); }
System.out.println("first thread exit"); } public void run() { try { for
(int i=0;i<5;i++) { System.out.println("Sleep time for thread 2:"+i);
Thread.sleep(1000); }
} catch (InterruptedException e) {System.out.println("thread has
wrong"); }
System.out.println("second thread exit"); } public static void
main(String args[]) { new twothread(); } }
執 行 結 果:java twothread
The running thread:Thread[The first main thread,5,main] creat another
thread first thread will sleep Sleep time for thread 2:0 Sleep time for
thread 2:1 Sleep time for thread 2:2 first thread exit Sleep time for
thread 2:3 Sleep time for thread 2:4 second thread exit
main線 程 用new Thread(this, "the second thread")創 建 了 一 個Thread
對 象, 通 過 傳 遞 第 一 個 參 數 來 標 明 新 線 程 來 調 用this對
象 的run函 數。 然 后 我 們 調 用start函 數, 它 將 使 線 程 從run
函 數 開 始 執 行。
7.1.3 同 步
因 為 多 線 程 給 你 提 ?copy; 了 程 序 的 異 步 執 行 的 功 能, 所
以 在 必 要 時 必 須 還 提 ?copy; 一 種 同 步 機 制。 例 如, 你 想 兩
個 線 程 通 訊 并 共 享 一 個 復 雜 的 數 據 結 構, 你 需 要 一 種 機
制 讓 他 們 相 互 牽 制 并 正 確 執 行。 為 這 個 目 的,Java用 一 種
叫 監 視 器(monitor)的 機 制 實 現 了 進 程 間 的 異 步 執 行。 可 以
將 監 視 器 看 作 是 一 個 很 小 的 盒 子, 它 只 能 容 納 一 個 線
程。 一 ?copy; 一 個 線 程 進 入 一 個 監 視 器, 所 有 其 他 線 程 必
須 等 到 第 一 個 線 程 退 出 監 視 器 后 才 能 進 入。 這 ?copy; 監
視 器 可 以 設 計 成 保 護 共 享 的 數 據 不 被 多 個 線 程 同 時 操
作。 大 多 數 多 線 程 系 統 將 這 ?copy; 監 視 器 設 計 成 對 象,Java
提 ?copy; 了 一 種 更 清 晰 的 解 決 方 案。 沒 有Monitor類; 每 個 對
象 通 過 將 他 們 的 成 員 函 數 定 義 成synchronized來 定 義 自 己
的 顯 式 監 視 器, 一 ?copy; 一 個 線 程 執 行 在 一 個synchronized
函 數 里, 其 他 任 何 線 程 都 不 能 調 用 同 一 個 對 象 的
synchronized函 數。
7.1.4 消 息
一 ?copy; 你 的 程 序 被 分 成 幾 個 邏 輯 線 程, 你 必 須 清 晰 的
知 道 這 ?copy; 線 程 ?reg; 間 應 怎 樣 相 互 通 訊。Java 提 ?copy; 了
wait和notify等 功 能 來 使 線 程 ?reg; 間 相 互 交 談。 一 個 線 程
可 以 進 入 某 一 個 對 象 的synchronized 函 數 進 入 等 待 狀 態,
直 到 其 他 線 程 顯 式 地 將 它 喚 醒。 可 以 有 多 個 線 程 進 入 同
一 個 函 數 并 等 待 同 一 個 喚 醒 消 息。
7.2 Java線 程 例 子
7.2.1 顯 式 定 義 線 程
在 我 們 的 單 線 程 應 用 程 序 里, 我 們 并 沒 有 看 見 線 程, 因
為Java能 自 動 創 建 和 控 制 你 的 線 程。 如 果 你 使 用 了 理 解
Java語 言 的 瀏 覽 器, 你 就 已 經 看 到 使 用 多 線 程 的Java程 序
了。 你 也 許 注 意 到 兩 個 小 程 序 可 以 同 時 運 行, 或 在 你 移
動 滾 動 條 時 小 程 序 繼 續 執 行。 這 并 不 是 表 明 小 程 序 是 多
線 程 的, 但 說 明 這 個 瀏 覽 器 是 多 線 程 的。 多 線 程 應 用 程
序(或applet)可 以 使 用 好 幾 個 執 行 上 下 文 來 完 成 它 們 的 工
作。 多 線 程 利 用 了 很 多 任 務 包 含 單 獨 的 可 分 離 的 子 任 務
的 特 點。 每 一 個 線 程 完 成 一 個 子 任 務。
但 是, 每 一 個 線 程 完 成 子 任 務 時 還 是 順 序 執 行 的。 一 個
多 線 程 程 序 允 許 各 個 線 程盡快 執 行 完 它 們。 這 種 特 點 會
有 更 好 的 實 時 輸 入 反 應。
7.2.2 多 線 程 例 子
下 面 這 個 例 子 創 建 了 三 個 單 獨 的 線 程, 它 們 分 別 打 印 自
己 的"Hello World":
//Define our simple threads.They will pause for a short time //and then
print out their names and delay times class TestThread extends Thread
{ private String whoami; private int delay;
//Our constructor to store the name (whoami) //and time to sleep (delay)
public TestThread(String s, int d) { whoami = s; delay = d; }
//Run - the thread method similar to main() //When run is finished, the
thread dies. //Run is called from the start() method of Thread public void
run() { //Try to sleep for the specified time try { sleep(delay); }
catch(InterruptedException e) {} //Now print out our name
System.out.println("Hello World!"+whoami+""+delay); } } /** * Multimtest.
A simple multithread thest program */ public class multitest { public
static void main(String args[]) { TestThread t1,t2,t3; //Create our test
threads t1 = new TestThread("Thread1",(int)(Math.readom()*2000)); t2 =
new TestThread("Thread2",(int)(Math.readom()*2000)); t3 = new
TestThread("Thread3",(int)(Math.readom()*2000));
//Start each of the threads t1.start(); t2.start(); t3.start(); } }
7.2.3 啟 動 一 個 線 程
程 序 啟 動 時 總 是 調 用main()函 數, 因 此main()是 我 們 創 建 和
啟 動 線 程 的 地 方:
t1 = new TestThread("Thread1",(int)(Math.readom()*2000));
這 一 行 創 建 了 一 個 新 的 線 程。 后 面 的 兩 個 參 數 傳 遞 了 線
程 的 名 稱 和 線 程 在 打 印 信 息 ?reg; 前 的 延 時 時 間。 因 為 我
們 直 接 控 制 線 程, 我 們 必 須 直 接 啟 動 它: t1.start();
7.2.4 操 作 線 程
如 果 創 建 線 程 正 常,t1應 包 含 一 個 有 效 的 執 行 線 程。 我 們
在 線 程 的run()函 數 里 控 制 線 程。 一 ?copy; 我 們 進 入run()函
數, 我 們 便 可 執 行 里 面 的 任 何 程 序。run()好 象main()一 樣。
一 ?copy;run() 執 行 完, 這 個 線 程 也 就 結 束 了。 在 這 個 例 子
里, 我 們 試 著 延 遲 一 個 隨 機 的 時 間(通 過 參 數 傳 遞?copy;:
sleep(delay);
sleep()函 數 只 是 簡 單 地 告 訴 線 程 休 息 多 少 個 毫 秒 時 間。
如 果 你 想 推 遲 一 個 線 程 的 執 行, 你 應 使 用sleep()函 數。 當
線 程 睡 眠 是sleep()并 不 占 用 系 統 資 源。 其 它 線 程 可 繼 續
工 作。 一 ?copy; 延 遲 時 間 完 畢, 它 將 打 印"Hello World"和 線 程
名 稱 及 延 遲 時 間。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -