熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

在Java程序中采用線程獲取優異性能

2013-11-23 19:54:00  來源: Java高級技術 

  什麼是線程?
  線程的概念並不難於掌握它是程序代碼的一個獨立的執行通道當多個線程執行時經由相同代碼的一個線程的通道通常與其它的不同例如假設一個線程執行一段相當於一個ifelse語句的if部分的字節代碼時而另一個線程正執行相當於else部分的字節代碼JVM怎樣保持對於每一個線程執行的跟蹤呢?JVM給每一個線程它自己的方法調用堆棧另外跟蹤當前指令字節代碼方法堆棧跟蹤本地變量JVM傳遞給一個方法的參數以及方法的返回值 
  當多個線程在同一個程序中執行字節代碼序列時這種行為叫作多線程多線程在多方面有利於程序 
  ·當執行其它任務時多線程GUI(圖形用戶界面)程序仍能保持對用戶的響應比如重編頁碼或打印一個文檔 
  ·帶線程的程序一般比它們沒有帶線程的副本程序完成得快這尤其表現在線程運行在一個多處理器機器上在這裡每一個線程都有它自己的處理器
  Java通過javalangThread類完成多線程每一個線程對象描述一個單獨的執行線程那些運行發生在線程的run()方法中因為缺省的run()方法什麼都不做你必須創建Thread子類並重載run()以完成有用的工作練習列表中領略一個在Thread中的線程及多線程 
  列表 ThreadDemojava 
  // ThreadDemojava
  class ThreadDemo
  {
  public static void main (String [] args)
  {
  MyThread mt = new MyThread ();
  mtstart ();
  for (int i = ; i < ; i++)
  Systemoutprintln (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++)
  Systemoutprint (*);
  Systemoutprint (\n);
  }
  }
  }
  列表顯示了一個由類ThreadDemo和MyThread組成的應用程序的源代碼類ThreadDemo通過創建一個MyThread對象驅動應用程序開始一個與其對象相關的線程並執行一段打印一個正方形表的代碼相反 MyThread重載Thread的run()方法打印(通過標准輸入流)一個由星形符號組成的直角三角形 
  當你鍵入java ThreadDemo運行應用程序時 JVM創建一個運行main()方法的開始線程通過執行mtstart ()開始線程告訴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()擲出一個javalangIllegalThreadStateException對象
  
  怎樣使用名稱
  在一個調試會話期間使用用戶友好方式從另一個線程區別其中一個線程證明是有幫助的要區分其中一個線程Java給一個線程取一個名稱Thread缺省的名稱是一個短線連字符和一個零開始的數字符號你可以接受Java的缺省線程名稱或選擇使用你自己的為了能夠自定義名稱Thread提供帶有name參數和一個setName(String name)方法的構造器Thread也提供一個getName()方法返回當前名稱顯示了怎樣通過Thread(String name)創建一個自定義名稱和通過在run()方法中調用getName()檢索當前名稱
  表NameThatThreadjava 
  // NameThatThreadjava
  class NameThatThread
  {
  public static void main (String [] args)
  {
  MyThread mt;
  if (argslength == )
  mt = new MyThread ();
  else
  mt = new MyThread (args []);
  mtstart ();
  }
  }
  class MyThread extends Thread
  {
  MyThread ()
  {
  //編譯器創建等價於super()的字節代碼
  }
  MyThread (String name)
  {
  super (name); //將名稱傳遞給Thread超類
  }
  public void run ()
  {
  Systemoutprintln (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
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.