鍍金池/ 教程/ Java/ Java 多線程
Java 接口
Java 方法
Java 數(shù)字
Java 條件判斷
Java 異常處理
Java 字符
Java 重寫
Java 網(wǎng)絡(luò)編程
Java 數(shù)據(jù)結(jié)構(gòu)
Java 的對(duì)象和類
Java 多線程
Java 封裝
Java 數(shù)組
Java Applet 基礎(chǔ)
Java 庫(kù)類
Java 抽象
Java 繼承
Java 正則表達(dá)式
Java 描述符的類型
Java 發(fā)送郵件
Java 序列化
Java 泛型
Java 多態(tài)
Java 變量類型
Java 基本數(shù)據(jù)類型
Java 包
Java 快速參考指南
Java 基本運(yùn)算符
Java 概述
Java 字符串
Java 循環(huán)控制
Java 環(huán)境設(shè)置
Java 文件注釋
Java 文件和 I/O
Java 集合
Java 基本語(yǔ)法
Java 日期和時(shí)間

Java 多線程

Java 是一種多線程編程語(yǔ)言,這意味著我們能用 java 開(kāi)發(fā)多線程程序。一個(gè)多線程程序包含兩個(gè)或更多的能并行運(yùn)行的部分,并且每一部分能最優(yōu)利用可用資源,尤其是當(dāng)你的計(jì)算機(jī)有多個(gè) CPU 時(shí),同時(shí)解決不同的任務(wù)。

多任務(wù)處理表示多個(gè)過(guò)程共同處理像CPU這樣共享的資源時(shí)。多線程將多任務(wù)處理的思想擴(kuò)展到應(yīng)用程序,你可以將一個(gè)單獨(dú)的應(yīng)用中的特定的操作細(xì)分為單獨(dú)的線程。每一個(gè)線程能并行地運(yùn)行。操作系統(tǒng)不僅在不同的應(yīng)用程序中劃分處理時(shí)間,而且在一個(gè)應(yīng)用程序中的每一個(gè)線程中也是如此。

多線程讓你可以用一種多個(gè)活動(dòng)能并行地在同一個(gè)程序中進(jìn)行的方法編寫程序。

線程的生命周期

一個(gè)線程在它的生命周期中通過(guò)不同的階段。例如,一個(gè)線程生成,開(kāi)始,運(yùn)行,然后死亡。下列的圖表展示了一個(gè)線程的完整的生命周期。

http://wiki.jikexueyuan.com/project/java/images/java_thread.jpg" alt="1" />

上述提到的階段在這解釋:

  • new: 一個(gè)新的線程以一個(gè)新的狀態(tài)開(kāi)始了它的生命周期。它始終留在這個(gè)狀態(tài)中直到程序開(kāi)始線程。它也被稱為一個(gè)生成的進(jìn)程。
  • Runnable: 在一個(gè)新生成的線程開(kāi)始后,這個(gè)線程變得可運(yùn)行。在這個(gè)狀態(tài)下的線程被認(rèn)為正在執(zhí)行任務(wù)。
  • Waiting: 有時(shí)候,一個(gè)線程當(dāng)它等待另一個(gè)線程工作時(shí)躍遷到等待狀態(tài)。一個(gè)線程僅當(dāng)另一個(gè)線程發(fā)信號(hào)給等待的線程繼續(xù)執(zhí)行才躍遷回可運(yùn)行轉(zhuǎn)態(tài)。
  • Timed waiting: 一個(gè)可運(yùn)行的線程能進(jìn)入定時(shí)等待狀態(tài)等待指定的時(shí)間間隔。在這種轉(zhuǎn)態(tài)下的線程當(dāng)時(shí)間間隔死亡或者當(dāng)它所等待的活動(dòng)發(fā)生時(shí)躍遷回可運(yùn)行狀態(tài)。
  • Terminated: 一個(gè)可運(yùn)行的線程,當(dāng)它完成了它的任務(wù)后進(jìn)入 terminated 狀態(tài),否則它就結(jié)束。

線程優(yōu)先級(jí)

每一個(gè) Java 線程有一個(gè)幫助操作系統(tǒng)決定線程調(diào)度順序的優(yōu)先級(jí)。

Java 線程的優(yōu)先級(jí)在 MIN_PRIORITY(一個(gè)為 1 的常數(shù))和 MAX_PRIORITY(一個(gè)為 10 的常數(shù))的范圍內(nèi)。缺省狀況下,每一個(gè)線程給予優(yōu)先級(jí) NORM_PRIORITY(一個(gè)為 5 的常數(shù))。

擁有更高優(yōu)先級(jí)的線程對(duì)于一個(gè)程序來(lái)說(shuō)更加重要,應(yīng)當(dāng)在低優(yōu)先級(jí)的線程前被分配處理時(shí)間。然而,線程優(yōu)先級(jí)不能保證線程執(zhí)行和所依賴的平臺(tái)。

通過(guò)實(shí)現(xiàn) Runnable 接口創(chuàng)建線程

如果你的類想要作為一個(gè)線程被執(zhí)行,那么你可以通過(guò)實(shí)現(xiàn) Runnable 接口來(lái)到達(dá)這個(gè)目的。你將需要遵從三個(gè)基本步驟:

步驟一:

作為第一步你需要實(shí)現(xiàn)由 Runnable 接口提供的 run() 方法。這個(gè)方法為線程提供了進(jìn)入點(diǎn)并且你將把你完全的業(yè)務(wù)邏輯放入方法中。下列是簡(jiǎn)單的 run() 方法語(yǔ)法:

public void run( )

步驟二:

在第二步你將使用以下的構(gòu)造函數(shù)實(shí)例化一個(gè) Thread 對(duì)象:

Thread(Runnable threadObj, String threadName);

threadObj 是實(shí)現(xiàn) Runnable 接口的類的一個(gè)實(shí)例,threadName 是給新線程的名字。

步驟三:

一旦 Thread 對(duì)象被創(chuàng)建,你可以通過(guò)調(diào)用 run() 方法的 start() 方法來(lái)開(kāi)始它。以下是 start() 方法的簡(jiǎn)單語(yǔ)法:

void start( );

示例

這里是一個(gè)創(chuàng)建一個(gè)新線程并使之運(yùn)行的例子:

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;

   RunnableDemo( String name){
       threadName = name;
       System.out.println("Creating " +  threadName );
   }
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
     } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
     }
     System.out.println("Thread " +  threadName + " exiting.");
   }

   public void start ()
   {
      System.out.println("Starting " +  threadName );
      if (t == null)
      {
         t = new Thread (this, threadName);
         t.start ();
      }
   }

}

public class TestThread {
   public static void main(String args[]) {

      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();

      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
   }   
}

這將產(chǎn)生以下結(jié)果:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

通過(guò)繼承 Thread 類來(lái)創(chuàng)建線程

第二個(gè)創(chuàng)建線程的方法是創(chuàng)建一個(gè)通過(guò)使用以下兩個(gè)簡(jiǎn)單步驟繼承 Thread 類的新的類。這個(gè)方法在解決 Thread 類中使用可行方法創(chuàng)建的多線程的問(wèn)題上提供了更多的靈活性。

步驟一:

你將需要覆寫 Thread 類中可用的 run()方法。這個(gè)方法為線程提供入口并且你將把你完全的業(yè)務(wù)邏輯放入方法中。以下是 run()方法的簡(jiǎn)單的語(yǔ)法。

public void run( )

步驟二:

一旦 Thread 對(duì)象被創(chuàng)建,你可以通過(guò)調(diào)用 run()方法的 start() 方法來(lái)開(kāi)始它。以下是 start() 方法的簡(jiǎn)單語(yǔ)法:

void start( );

示例

這是前面的重寫繼承 Thread 的程序:

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;

   ThreadDemo( String name){
       threadName = name;
       System.out.println("Creating " +  threadName );
   }
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
     } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
     }
     System.out.println("Thread " +  threadName + " exiting.");
   }

   public void start ()
   {
      System.out.println("Starting " +  threadName );
      if (t == null)
      {
         t = new Thread (this, threadName);
         t.start ();
      }
   }

}

public class TestThread {
   public static void main(String args[]) {

      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();

      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.start();
   }   
}

這將會(huì)產(chǎn)生以下結(jié)果:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Thread 方法

以下是在 Thread 類中可以獲得的重要方法的列表。

SN 接口描述
1 Methods with Description
在一個(gè)獨(dú)立的執(zhí)行路徑中開(kāi)始一個(gè)線程,然后在這個(gè) Thread 對(duì)象上調(diào)用 run() 方法。
2 public void run()
如果這個(gè) Thread 對(duì)象是使用一個(gè)單獨(dú)的 Runnable 目標(biāo)實(shí)例化的,run()方法被 Runnable 對(duì)象調(diào)用。
3 public final void setName(String name)
改變 Thread 對(duì)象的名字。也有一個(gè) getName()方法來(lái)檢索名字。
4 public final void setPriority(int priority)
設(shè)置 Thread 對(duì)象的優(yōu)先級(jí)??赡艿闹翟?1 到 10 之間。
5 public final void setDaemon(boolean on)
一個(gè)真值將這個(gè)線程標(biāo)志為守護(hù)進(jìn)程。
6 public final void join(long millisec)
當(dāng)前進(jìn)程在第二個(gè)線程上調(diào)用這個(gè)方法,使得當(dāng)前進(jìn)程阻塞直到第二個(gè)線程終結(jié)或者指定的毫秒數(shù)過(guò)去。
7 public void interrupt()
中斷這個(gè)進(jìn)程,如果由于任何原因而阻塞,使得它也繼續(xù)執(zhí)行。
8 public final boolean isAlive()
如果線程是活的,返回真值,可在線程已經(jīng)開(kāi)始但在運(yùn)行到完成之前的任何時(shí)間。

以前的方法是被一個(gè)特殊的 Thread 對(duì)象調(diào)用的。以下在 Thread 類中的方法是靜態(tài)的。調(diào)用靜態(tài)方法會(huì)在當(dāng)前運(yùn)行的線程上執(zhí)行操作。

SN 接口描述
1 public static void yield()
使得當(dāng)前正在運(yùn)行的線程讓步于任何其他相同優(yōu)先級(jí)的正在等待調(diào)度的線程。
2 public static void sleep(long millisec)
使當(dāng)前運(yùn)行的線程阻塞至少指定的毫秒數(shù)。
3 public static boolean holdsLock(Object x)
如果當(dāng)前線程持有給定對(duì)象的鎖,返回真值。
4 public static Thread currentThread()
返回對(duì)當(dāng)前運(yùn)行的線程的引用,也就是調(diào)用這個(gè)方法的線程。
5 public static void dumpStack()
為當(dāng)前運(yùn)行的線程打印堆棧跟蹤,這在當(dāng)調(diào)試多線程應(yīng)用程序時(shí)是有用的。

示例

以下 ThreadClassDemo 程序展示了一些 Thread 類的方法??紤]實(shí)現(xiàn) Runnable 的類 DisplayMessage:

// File Name : DisplayMessage.java
// Create a thread to implement Runnable
public class DisplayMessage implements Runnable
{
   private String message;
   public DisplayMessage(String message)
   {
      this.message = message;
   }
   public void run()
   {
      while(true)
      {
         System.out.println(message);
      }
   }
}

以下是繼承 Thread 類的另一個(gè)類:

// File Name : GuessANumber.java
// Create a thread to extentd Thread
public class GuessANumber extends Thread
{
   private int number;
   public GuessANumber(int number)
   {
      this.number = number;
   }
   public void run()
   {
      int counter = 0;
      int guess = 0;
      do
      {
          guess = (int) (Math.random() * 100 + 1);
          System.out.println(this.getName()
                       + " guesses " + guess);
          counter++;
      }while(guess != number);
      System.out.println("** Correct! " + this.getName()
                       + " in " + counter + " guesses.**");
   }
}

以下是使用上面定義的類的主程序:

// File Name : ThreadClassDemo.java
public class ThreadClassDemo
{
   public static void main(String [] args)
   {
      Runnable hello = new DisplayMessage("Hello");
      Thread thread1 = new Thread(hello);
      thread1.setDaemon(true);
      thread1.setName("hello");
      System.out.println("Starting hello thread...");
      thread1.start();

      Runnable bye = new DisplayMessage("Goodbye");
      Thread thread2 = new Thread(bye);
      thread2.setPriority(Thread.MIN_PRIORITY);
      thread2.setDaemon(true);
      System.out.println("Starting goodbye thread...");
      thread2.start();

      System.out.println("Starting thread3...");
      Thread thread3 = new GuessANumber(27);
      thread3.start();
      try
      {
         thread3.join();
      }catch(InterruptedException e)
      {
         System.out.println("Thread interrupted.");
      }
      System.out.println("Starting thread4...");
      Thread thread4 = new GuessANumber(75);

      thread4.start();
      System.out.println("main() is ending...");
   }
}

這將產(chǎn)生以下結(jié)果。你可以一次一次地嘗試這個(gè)例子并且你將每次得到不同的結(jié)果。

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......