明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線(xiàn)學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

Java多線(xiàn)程編程精要之完成線(xiàn)程

[摘要]使用 Java 編程語(yǔ)言實(shí)現(xiàn)線(xiàn)程   Java編程語(yǔ)言使多線(xiàn)程如此簡(jiǎn)單有效,以致于某些程序員說(shuō)它實(shí)際上是自然的。盡管在 Java 中使用線(xiàn)程比在其他語(yǔ)言中要容易得多,仍然有恍└拍钚枰莆鍘R親〉囊患匾氖慮槭?main() 函數(shù)也是一個(gè)線(xiàn)程,并可用來(lái)做有用的工作。程序員只有在需要多個(gè)線(xiàn)程時(shí)才需...
使用 Java 編程語(yǔ)言實(shí)現(xiàn)線(xiàn)程

  Java編程語(yǔ)言使多線(xiàn)程如此簡(jiǎn)單有效,以致于某些程序員說(shuō)它實(shí)際上是自然的。盡管在 Java 中使用線(xiàn)程比在其他語(yǔ)言中要容易得多,仍然有恍└拍钚枰莆鍘R親〉囊患匾氖慮槭?main() 函數(shù)也是一個(gè)線(xiàn)程,并可用來(lái)做有用的工作。程序員只有在需要多個(gè)線(xiàn)程時(shí)才需要?jiǎng)?chuàng)建新的線(xiàn)程。

  Thread 類(lèi)

  Thread 類(lèi)是一個(gè)具體的類(lèi),即不是抽象類(lèi),該類(lèi)封裝了線(xiàn)程的行為。要?jiǎng)?chuàng)建一個(gè)線(xiàn)程,程序員必須創(chuàng)建一個(gè)從 Thread 類(lèi)導(dǎo)出的新類(lèi)。程序員必須覆蓋 Thread 的 run() 函數(shù)來(lái)完成有用的工作。用戶(hù)并不直接調(diào)用此函數(shù);而是必須調(diào)用 Thread 的 start() 函數(shù),該函數(shù)再調(diào)用 run()。下面的代碼說(shuō)明了它的用法:

  創(chuàng)建兩個(gè)新線(xiàn)程

  import java.util.*;

  class TimePrinter extends Thread {
  int pauseTime;
  String name;
  public TimePrinter(int x, String n) {
  pauseTime = x;
  name = n;
  }

  public void run() {
  while(true) {
   try {
    System.out.println(name + ":" + new Date(System.currentTimeMillis()));
    Thread.sleep(pauseTime);
   } catch(Exception e) {
    System.out.println(e);
   }
  }
  }

  static public void main(String args[]) {
  TimePrinter tp1 = new TimePrinter(1000, "Fast Guy");
  tp1.start();
  TimePrinter tp2 = new TimePrinter(3000, "Slow Guy");
  tp2.start();

  }
  }

  在本例中,我們可以看到一個(gè)簡(jiǎn)單的程序,它按兩個(gè)不同的時(shí)間間隔(1 秒和 3 秒)在屏幕上顯示當(dāng)前時(shí)間。這是通過(guò)創(chuàng)建兩個(gè)新線(xiàn)程來(lái)完成的,包括 main() 共三個(gè)線(xiàn)程。但是,因?yàn)橛袝r(shí)要作為線(xiàn)程運(yùn)行的類(lèi)可能已經(jīng)是某個(gè)類(lèi)層次的一部分,所以就不能再按這種機(jī)制創(chuàng)建線(xiàn)程。雖然在同一個(gè)類(lèi)中可以實(shí)現(xiàn)任意數(shù)量的接口,但 Java 編程語(yǔ)言只允許一個(gè)類(lèi)有一個(gè)父類(lèi)。同時(shí),某些程序員避免從 Thread 類(lèi)導(dǎo)出,因?yàn)樗鼜?qiáng)加了類(lèi)層次。對(duì)于這種情況,就要 runnable 接口。

  Runnable 接口

  此接口只有一個(gè)函數(shù),run(),此函數(shù)必須由實(shí)現(xiàn)了此接口的類(lèi)實(shí)現(xiàn)。但是,就運(yùn)行這個(gè)類(lèi)而論,其語(yǔ)義與前一個(gè)示例稍有不同。我們可以用 runnable 接口改寫(xiě)前一個(gè)示例。(不同的部分用黑體表示。)

  創(chuàng)建兩個(gè)新線(xiàn)程而不強(qiáng)加類(lèi)層次

  import java.util.*;

  class TimePrinter implements Runnable {
  int pauseTime;
  String name;
  public TimePrinter(int x, String n) {
  pauseTime = x;
  name = n;
  }

  public void run() {
  while(true) {
   try {
    System.out.println(name + ":" + new Date(System.currentTimeMillis()));
    Thread.sleep(pauseTime);
   } catch(Exception e) {
    System.out.println(e);
   }
  }
  }

  static public void main(String args[]) {
  Thread t1 = new Thread(new TimePrinter(1000, "Fast Guy"));
  t1.start();
  Thread t2 = new Thread(new TimePrinter(3000, "Slow Guy"));
  t2.start();
  }
  }


  請(qǐng)注意,當(dāng)使用 runnable 接口時(shí),您不能直接創(chuàng)建所需類(lèi)的對(duì)象并運(yùn)行它;必須從 Thread 類(lèi)的一個(gè)實(shí)例內(nèi)部運(yùn)行它。許多程序員更喜歡 runnable 接口,因?yàn)閺?Thread 類(lèi)繼承會(huì)強(qiáng)加類(lèi)層次。

  synchronized 關(guān)鍵字

  到目前為止,我們看到的示例都只是以非常簡(jiǎn)單的方式來(lái)利用線(xiàn)程。只有最小的數(shù)據(jù)流,而且不會(huì)出現(xiàn)兩個(gè)線(xiàn)程訪(fǎng)問(wèn)同一個(gè)對(duì)象的情況。但是,在大多數(shù)有用的程序中,線(xiàn)程之間通常有信息流。試考慮一個(gè)金融應(yīng)用程序,它有一個(gè) Account 對(duì)象,如下例中所示:

  一個(gè)銀行中的多項(xiàng)活動(dòng)

  public class Account {
  String holderName;
  float amount;
  public Account(String name, float amt) {
  holderName = name;
  amount = amt;
  }

  public void deposit(float amt) {
  amount += amt;
  }

  public void withdraw(float amt) {
  amount -= amt;
  }

  public float checkBalance() {
  return amount;
  }
  }

  在此代碼樣例中潛伏著一個(gè)錯(cuò)誤。如果此類(lèi)用于單線(xiàn)程應(yīng)用程序,不會(huì)有任何問(wèn)題。但是,在多線(xiàn)程應(yīng)用程序的情況中,不同的線(xiàn)程就有可能同時(shí)訪(fǎng)問(wèn)同一個(gè) Account 對(duì)象,比如說(shuō)一個(gè)聯(lián)合帳戶(hù)的所有者在不同的 ATM 上同時(shí)進(jìn)行訪(fǎng)問(wèn)。在這種情況下,存入和支出就可能以這樣的方式發(fā)生:一個(gè)事務(wù)被另一個(gè)事務(wù)覆蓋。這種情況將是災(zāi)難性的。但是,Java 編程語(yǔ)言提供了一種簡(jiǎn)單的機(jī)制來(lái)防止發(fā)生這種覆蓋。每個(gè)對(duì)象在運(yùn)行時(shí)都有一個(gè)關(guān)聯(lián)的鎖。這個(gè)鎖可通過(guò)為方法添加關(guān)鍵字 synchronized 來(lái)獲得。這樣,修訂過(guò)的 Account 對(duì)象(如下所示)將不會(huì)遭受像數(shù)據(jù)損壞這樣的錯(cuò)誤:

  對(duì)一個(gè)銀行中的多項(xiàng)活動(dòng)進(jìn)行同步處理

  public class Account {
  String holderName;
  float amount;
  public Account(String name, float amt) {
  holderName = name;
  amount = amt;
  }

  public synchronized void deposit(float amt) {
  amount += amt;
  }

  public synchronized void withdraw(float amt) {
  amount -= amt;
  }

  public float checkBalance() {
  return amount;
  }
  }

  deposit() 和 withdraw() 函數(shù)都需要這個(gè)鎖來(lái)進(jìn)行操作,所以當(dāng)一個(gè)函數(shù)運(yùn)行時(shí),另一個(gè)函數(shù)就被阻塞。請(qǐng)注意, checkBalance() 未作更改,它嚴(yán)格是一個(gè)讀函數(shù)。因?yàn)?checkBalance() 未作同步處理,所以任何其他方法都不會(huì)阻塞它,它也不會(huì)阻塞任何其他方法,不管那些方法是否進(jìn)行了同步處理。