劉誌梅201771010115.《面向對象程序設計(java)》第十六周學習總結
實驗十六 線程技術
實驗時間 2017-12-8
1、實驗目的與要求
(1)當線程的run方法執行方法體中最後一條語句後,並經由執行return語句返回時,或者出現了在方法中沒有捕獲的異常時,線程將終止。
當對一個線程調用interrupt方法時,線程的中斷狀態將被置位。
每個線程都應該檢查boolean標誌,以判斷線程是否被中斷。
如果線程被阻塞,無法檢測中斷狀態。
當在一個被阻塞的線程上調用interrupt方法時,阻塞調用將會被interrupt Exception異常中斷。
(2) 線程的6種狀態:New(新創建)、Runnable(可運行)、Bloced(被阻塞)、Waiting(等待)、Timed waiting(計時等待)、Terminated(被終止)。
當一個線程處於新創建狀態時,程序還沒有開始運行程序中的代碼。
一旦調用start方法,線程處於runnable狀態。
一個可運行的線程可能正在運行也可能沒有運行,這取決於操作系統給線程提供運行的時間。
在具有多個處理器的機器上,每一個處理器運行一個線程,可以有多個線程並行運行。
當一個線程試圖獲取一個內部的對象鎖,而該鎖被其他線程持有,則該線程進入阻塞狀態;當一個線程等待另一個線程通知調度器一個條件時,它自己進入等待狀態;有幾個方法有一個超時參數,調用它們線程進入計時等待狀態。
線程被終止的原因有如下兩個:因為run方法正常退出而自然死亡;因為一個沒有捕獲的異常終止了run方法而意外死亡。
(3) 線程屬性包括:線程優先級、守護線程、線程組以及處理未捕獲異常的處理器。
在JAVA程序設計語言中,每一個線程有一個優先級;默認情況下,一個線程繼承它的父線程的優先級,可以用setPriority方法提高或降低任何一個線程的優先級。
優先級可以設置為在MIN_PRIORITY(在Thread的類中定義為1)與MAX_PRIORITY(定義為10)之間的任何值;NORM_PRIORITY被定義為5。
可以通過調用t.setDaemon(true);將線程轉換為守護線程。
線程的run方法不能拋出任何受查異常,但是,非受查異常會導致線程終止。
線程組是一個可以統一管理的線程集合。
(4) 在大多數實際的多線程應用中,兩個或兩個以上的線程需要共享對同一數據的存取;如果兩個線程存取相同的對象,並且每一個線程都調用了一個修改該對象狀態的方法,此時這種情況稱為競爭條件。
(5) 每一個Back對象都有自己的ReentrantLock對象,如果兩個線程試圖訪問同一個Back對象,那麽鎖以串行方式提供服務。
鎖和條件的關鍵之處:鎖用來保護代碼片段,任何時刻只能有一個線程執行被保護的代碼;鎖可以管理任何試圖進入被保護代碼段的線程;鎖可以擁有一個或多個相關的條件對象;每個條件對象管理那些已經進入被保護的代碼段但還不能運行的線程。
內部鎖和條件存在的一些局限:不能中斷一個正在試圖獲得鎖的線程;試圖獲得鎖時不能設定超時;每個鎖僅有單一的條件,這可能是不夠的。
(6)監視器的特性:監視器是只包含私有域的類;每一個監視器類的對象都有一個相關的鎖;使用該鎖對所有的方法進行加鎖;該鎖可以有任意多個相關條件。
在下述三個方面java對象不同於監視器,從而使得線程的安全性下降:域不要求必須是private;方法不要求必須是synchronized;內部鎖對客戶是可用的。
Volatile關鍵字為實例域的同步訪問提供了一種免鎖機制。
除非使用鎖或Volatile修飾符,否則無法從多個線程安全的讀取一個域。
假設對共享變量除了賦值之外並不完成其它操作,那麽可以將這些共享變量聲明為Volatile。
如果另一個線程也在更新largest,就可能阻止這個線程更新。
有可能因為每一個線程要等待更多的錢款存入而導致所有線程都阻塞,這樣的狀態被稱為死鎖。
(7)Swing不是線程安全的。
將線程與Swing一起使用時,必須遵守的兩個簡單原則:如果一個動作需要花費很長時間,在一個獨立的工作器線程中做這件事不要在事件分配線程中做;除了事件分配線程,不要在任何線程中接觸Swing組件。
2、實驗內容和步驟
實驗1:測試程序並進行代碼註釋。
測試程序1:
l 在elipse IDE中調試運行ThreadTest,結合程序運行結果理解程序;
l 掌握線程概念;
l 掌握用Thread的擴展類實現線程的方法;
l 利用Runnable接口改造程序,掌握用Runnable接口創建線程的方法。
class Lefthand extends Thread { public void run() { for(int i=0;i<=5;i++) { System.out.println("You are Students!"); try{ sleep(500); } catch(InterruptedException e) { System.out.println("Lefthand error.");} } } } class Righthand extends Thread { public void run() { for(int i=0;i<=5;i++) { System.out.println("I am a Teacher!"); try{ sleep(300); } catch(InterruptedException e) { System.out.println("Righthand error.");} } } } public class ThreadTest { static Lefthand left; static Righthand right; public static void main(String[] args) { left=new Lefthand(); right=new Righthand(); left.start(); right.start(); } } |
class Lefthand implements Runnable { public void run() { for (int i = 0; i <= 5; i++) { System.out.println("You are Students!"); try { Thread.sleep(500); } // 休眠時間為500毫秒 catch (InterruptedException e)// 阻塞狀態 { System.out.println("Lefthand error."); } } } } class Righthand implements Runnable { public void run() { for (int i = 0; i <= 5; i++) { System.out.println("I am a Teacher!"); try { Thread.sleep(300); } // 休眠時間為300毫秒 catch (InterruptedException e) { System.out.println("Righthand error."); } // } } } public class thresdtest { private static Runnable Right; public static void main(String[] args) { Righthand righthand = new Righthand(); Thread right = new Thread(righthand); right.start(); Lefthand lefthand=new Lefthand(); Thread left = new Thread(lefthand); left.start(); } }
修改後:
class Lefthand implements Runnable { public void run() { for (int i = 0; i <= 5; i++) { System.out.println("You are Students!"); try { Thread.sleep(500); } // 休眠時間為500毫秒 catch (InterruptedException e)// 阻塞狀態 { System.out.println("Lefthand error."); } } } } class Righthand implements Runnable { public void run() { for (int i = 0; i <= 5; i++) { System.out.println("I am a Teacher!"); try { Thread.sleep(300); } // 休眠時間為300毫秒 catch (InterruptedException e) { System.out.println("Righthand error."); } // } } } public class thresdtest { private static Runnable Right; public static void main(String[] args) { Righthand righthand = new Righthand(); Lefthand lefthand=new Lefthand(); Thread right = new Thread(righthand); Thread left = new Thread(lefthand); right.start(); left.start(); } }
測試程序2:
l 在Elipse環境下調試教材625頁程序14-1、14-2 、14-3,結合程序運行結果理解程序;
l 在Elipse環境下調試教材631頁程序14-4,結合程序運行結果理解程序;
l 對比兩個程序,理解線程的概念和用途;
l 掌握線程創建的兩種技術。
測試程序3:分析以下程序運行結果並理解程序。
class Race extends Thread { public static void main(String args[]) { Race[] runner=new Race[4]; for(int i=0;i<4;i++) runner[i]=new Race( ); for(int i=0;i<4;i++) runner[i].start( ); runner[1].setPriority(MIN_PRIORITY); runner[3].setPriority(MAX_PRIORITY);} public void run( ) { for(int i=0; i<1000000; i++); System.out.println(getName()+"線程的優先級是"+getPriority()+"已計算完畢!"); } } |
測試程序4
l 教材642頁程序模擬一個有若幹賬戶的銀行,隨機地生成在這些賬戶之間轉移錢款的交易。每一個賬戶有一個線程。在每一筆交易中,會從線程所服務的賬戶中隨機轉移一定數目的錢款到另一個隨機賬戶。
l 在Elipse環境下調試教材642頁程序14-5、14-6,結合程序運行結果理解程序;
綜合編程練習
編程練習1
1. 設計一個用戶信息采集程序,要求如下:
(1) 用戶信息輸入界面如下圖所示:
(2) 用戶點擊提交按鈕時,用戶輸入信息顯示控制臺界面;
(3) 用戶點擊重置按鈕後,清空用戶已輸入信息;
(4) 點擊窗口關閉,程序退出。
2.創建兩個線程,每個線程按順序輸出5次“你好”,每個“你好”要標明來自哪個線程及其順序號。
3. 完善實驗十五 GUI綜合編程練習程序。
劉誌梅201771010115.《面向對象程序設計(java)》第十六周學習總結