国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Manual Tutorial JAVA / Java 多線(xiàn)程編程

Java 多線(xiàn)程編程

Java給多線(xiàn)程編程提供了內(nèi)置的支持。一個(gè)多線(xiàn)程程序包含兩個(gè)或多個(gè)能并發(fā)運(yùn)行的部分。程序的每一部分都稱(chēng)作一個(gè)線(xiàn)程,并且每個(gè)線(xiàn)程定義了一個(gè)獨(dú)立的執(zhí)行路徑。

多線(xiàn)程是多任務(wù)的一種特別的形式,但多線(xiàn)程使用了更小的資源開(kāi)銷(xiāo)。

這里定義和線(xiàn)程相關(guān)的另一個(gè)術(shù)語(yǔ) - 進(jìn)程:一個(gè)進(jìn)程包括由操作系統(tǒng)分配的內(nèi)存空間,包含一個(gè)或多個(gè)線(xiàn)程。一個(gè)線(xiàn)程不能獨(dú)立的存在,它必須是進(jìn)程的一部分。一個(gè)進(jìn)程一直運(yùn)行,直到所有的非守候線(xiàn)程都結(jié)束運(yùn)行后才能結(jié)束。

多線(xiàn)程能滿(mǎn)足程序員編寫(xiě)高效率的程序來(lái)達(dá)到充分利用CPU的目的。


一個(gè)線(xiàn)程的生命周

線(xiàn)程經(jīng)過(guò)其生命周期的各個(gè)階段。下圖顯示了一個(gè)線(xiàn)程完整的生命周期。

java-thread.jpg

  • 新建狀態(tài):

    使用 new 關(guān)鍵字和 Thread 類(lèi)或其子類(lèi)建立一個(gè)線(xiàn)程對(duì)象后,該線(xiàn)程對(duì)象就處于新建狀態(tài)。它保持這個(gè)狀態(tài)直到程序 start() 這個(gè)線(xiàn)程。

  • 就緒狀態(tài):

    當(dāng)線(xiàn)程對(duì)象調(diào)用了start()方法之后,該線(xiàn)程就進(jìn)入就緒狀態(tài)。就緒狀態(tài)的線(xiàn)程處于就緒隊(duì)列中,要等待JVM里線(xiàn)程調(diào)度器的調(diào)度。

  • 運(yùn)行狀態(tài):

    如果就緒狀態(tài)的線(xiàn)程獲取 CPU 資源,就可以執(zhí)行 run(),此時(shí)線(xiàn)程便處于運(yùn)行狀態(tài)。處于運(yùn)行狀態(tài)的線(xiàn)程最為復(fù)雜,它可以變?yōu)樽枞麪顟B(tài)、就緒狀態(tài)和死亡狀態(tài)。

  • 阻塞狀態(tài):

    如果一個(gè)線(xiàn)程執(zhí)行了sleep(睡眠)、suspend(掛起)等方法,失去所占用資源之后,該線(xiàn)程就從運(yùn)行狀態(tài)進(jìn)入阻塞狀態(tài)。在睡眠時(shí)間已到或獲得設(shè)備資源后可以重新進(jìn)入就緒狀態(tài)。

  • 死亡狀態(tài):

    一個(gè)運(yùn)行狀態(tài)的線(xiàn)程完成任務(wù)或者其他終止條件發(fā)生時(shí),該線(xiàn)程就切換到終止?fàn)顟B(tài)。


線(xiàn)程的優(yōu)先級(jí)

每一個(gè)Java線(xiàn)程都有一個(gè)優(yōu)先級(jí),這樣有助于操作系統(tǒng)確定線(xiàn)程的調(diào)度順序。

Java線(xiàn)程的優(yōu)先級(jí)是一個(gè)整數(shù),其取值范圍是1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。

默認(rèn)情況下,每一個(gè)線(xiàn)程都會(huì)分配一個(gè)優(yōu)先級(jí)NORM_PRIORITY(5)。

具有較高優(yōu)先級(jí)的線(xiàn)程對(duì)程序更重要,并且應(yīng)該在低優(yōu)先級(jí)的線(xiàn)程之前分配處理器資源。但是,線(xiàn)程優(yōu)先級(jí)不能保證線(xiàn)程執(zhí)行的順序,而且非常依賴(lài)于平臺(tái)。


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

Java提供了兩種創(chuàng)建線(xiàn)程方法:

  • 通過(guò)實(shí)現(xiàn)Runable接口;

  • 通過(guò)繼承Thread類(lèi)本身。


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

創(chuàng)建一個(gè)線(xiàn)程,最簡(jiǎn)單的方法是創(chuàng)建一個(gè)實(shí)現(xiàn)Runnable接口的類(lèi)。

為了實(shí)現(xiàn)Runnable,一個(gè)類(lèi)只需要執(zhí)行一個(gè)方法調(diào)用run(),聲明如下:


public void run()

你可以重寫(xiě)該方法,重要的是理解的run()可以調(diào)用其他方法,使用其他類(lèi),并聲明變量,就像主線(xiàn)程一樣。

在創(chuàng)建一個(gè)實(shí)現(xiàn)Runnable接口的類(lèi)之后,你可以在類(lèi)中實(shí)例化一個(gè)線(xiàn)程對(duì)象。

Thread定義了幾個(gè)構(gòu)造方法,下面的這個(gè)是我們經(jīng)常使用的:

Thread(Runnable threadOb,String threadName);

這里,threadOb 是一個(gè)實(shí)現(xiàn)Runnable 接口的類(lèi)的實(shí)例,并且 threadName指定新線(xiàn)程的名字。

新線(xiàn)程創(chuàng)建之后,你調(diào)用它的start()方法它才會(huì)運(yùn)行。

void start();

實(shí)例

下面是一個(gè)創(chuàng)建線(xiàn)程并開(kāi)始讓它執(zhí)行的實(shí)例:

// 創(chuàng)建一個(gè)新的線(xiàn)程
class NewThread implements Runnable {
   Thread t;
   NewThread() {
      // 創(chuàng)建第二個(gè)新線(xiàn)程
      t = new Thread(this, "Demo Thread");
      System.out.println("Child thread: " + t);
      t.start(); // 開(kāi)始線(xiàn)程
   }
  
   // 第二個(gè)線(xiàn)程入口
   public void run() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Child Thread: " + i);
            // 暫停線(xiàn)程
            Thread.sleep(50);
         }
     } catch (InterruptedException e) {
         System.out.println("Child interrupted.");
     }
     System.out.println("Exiting child thread.");
   }
}
 
public class ThreadDemo {
   public static void main(String args[]) {
      new NewThread(); // 創(chuàng)建一個(gè)新線(xiàn)程
      try {
         for(int i = 5; i > 0; i--) {
           System.out.println("Main Thread: " + i);
           Thread.sleep(100);
         }
      } catch (InterruptedException e) {
         System.out.println("Main thread interrupted.");
      }
      System.out.println("Main thread exiting.");
   }
}

編譯以上程序運(yùn)行結(jié)果如下:

Child thread: Thread[Demo Thread,5,main]
Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.

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

創(chuàng)建一個(gè)線(xiàn)程的第二種方法是創(chuàng)建一個(gè)新的類(lèi),該類(lèi)繼承Thread類(lèi),然后創(chuàng)建一個(gè)該類(lèi)的實(shí)例。

繼承類(lèi)必須重寫(xiě)run()方法,該方法是新線(xiàn)程的入口點(diǎn)。它也必須調(diào)用start()方法才能執(zhí)行。

實(shí)例

// 通過(guò)繼承 Thread 創(chuàng)建線(xiàn)程
class NewThread extends Thread {
   NewThread() {
      // 創(chuàng)建第二個(gè)新線(xiàn)程
      super("Demo Thread");
      System.out.println("Child thread: " + this);
      start(); // 開(kāi)始線(xiàn)程
   }
 
   // 第二個(gè)線(xiàn)程入口
   public void run() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Child Thread: " + i);
                            // 讓線(xiàn)程休眠一會(huì)
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Child interrupted.");
      }
      System.out.println("Exiting child thread.");
   }
}
 
public class ExtendThread {
   public static void main(String args[]) {
      new NewThread(); // 創(chuàng)建一個(gè)新線(xiàn)程
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Main Thread: " + i);
            Thread.sleep(100);
         }
      } catch (InterruptedException e) {
         System.out.println("Main thread interrupted.");
      }
      System.out.println("Main thread exiting.");
   }
}

編譯以上程序運(yùn)行結(jié)果如下:

Child thread: Thread[Demo Thread,5,main]
Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.

Thread 方法

下表列出了Thread類(lèi)的一些重要方法:

序號(hào)方法描述
                    1public void start()
使該線(xiàn)程開(kāi)始執(zhí)行;Java 虛擬機(jī)調(diào)用該線(xiàn)程的 run 方法。
                    2public void run()
如果該線(xiàn)程是使用獨(dú)立的 Runnable 運(yùn)行對(duì)象構(gòu)造的,則調(diào)用該 Runnable 對(duì)象的 run 方法;否則,該方法不執(zhí)行任何操作并返回。
                    3public final void setName(String name)
改變線(xiàn)程名稱(chēng),使之與參數(shù) name 相同。
                    4public final void setPriority(int priority)
 更改線(xiàn)程的優(yōu)先級(jí)。
                    5public final void setDaemon(boolean on)
將該線(xiàn)程標(biāo)記為守護(hù)線(xiàn)程或用戶(hù)線(xiàn)程。
                    6public final void join(long millisec)
等待該線(xiàn)程終止的時(shí)間最長(zhǎng)為 millis 毫秒。
                    7public void interrupt()
中斷線(xiàn)程。
                    8public final boolean isAlive()
測(cè)試線(xiàn)程是否處于活動(dòng)狀態(tài)。

測(cè)試線(xiàn)程是否處于活動(dòng)狀態(tài)。 上述方法是被Thread對(duì)象調(diào)用的。下面的方法是Thread類(lèi)的靜態(tài)方法。

序號(hào)方法描述
                    1public static void yield()
暫停當(dāng)前正在執(zhí)行的線(xiàn)程對(duì)象,并執(zhí)行其他線(xiàn)程。
                    2public static void sleep(long millisec)
在指定的毫秒數(shù)內(nèi)讓當(dāng)前正在執(zhí)行的線(xiàn)程休眠(暫停執(zhí)行),此操作受到系統(tǒng)計(jì)時(shí)器和調(diào)度程序精度和準(zhǔn)確性的影響。
                    3public static boolean holdsLock(Object x)
當(dāng)且僅當(dāng)當(dāng)前線(xiàn)程在指定的對(duì)象上保持監(jiān)視器鎖時(shí),才返回 true。
                    4public static Thread currentThread()
返回對(duì)當(dāng)前正在執(zhí)行的線(xiàn)程對(duì)象的引用。
                    5public static void dumpStack()
將當(dāng)前線(xiàn)程的堆棧跟蹤打印至標(biāo)準(zhǔn)錯(cuò)誤流。

實(shí)例

如下的ThreadClassDemo 程序演示了Thread類(lèi)的一些方法:

// 文件名 : DisplayMessage.java
// 通過(guò)實(shí)現(xiàn) Runnable 接口創(chuàng)建線(xiàn)程
public class DisplayMessage implements Runnable
{
   private String message;
   public DisplayMessage(String message)
   {
      this.message = message;
   }
   public void run()
   {
      while(true)
      {
         System.out.println(message);
      }
   }
}
// 文件名 : GuessANumber.java
// 通過(guò)繼承 Thread 類(lèi)創(chuàng)建線(xiàn)程

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.**");
   }
}
// 文件名 : 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...");
   }
}

運(yùn)行結(jié)果如下,每一次運(yùn)行的結(jié)果都不一樣。

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Thread-2 guesses 27
Hello
** Correct! Thread-2 in 102 guesses.**
Hello
Starting thread4...
Hello
Hello
..........remaining result produced.

線(xiàn)程的幾個(gè)主要概念:

在多線(xiàn)程編程時(shí),你需要了解以下幾個(gè)概念:

  • 線(xiàn)程同步

  • 線(xiàn)程間通信

  • 線(xiàn)程死鎖

  • 線(xiàn)程控制:掛起、停止和恢復(fù)


多線(xiàn)程的使用

有效利用多線(xiàn)程的關(guān)鍵是理解程序是并發(fā)執(zhí)行而不是串行執(zhí)行的。例如:程序中有兩個(gè)子系統(tǒng)需要并發(fā)執(zhí)行,這時(shí)候就需要利用多線(xiàn)程編程。

通過(guò)對(duì)多線(xiàn)程的使用,可以編寫(xiě)出非常高效的程序。不過(guò)請(qǐng)注意,如果你創(chuàng)建太多的線(xiàn)程,程序執(zhí)行的效率實(shí)際上是降低了,而不是提升了。

請(qǐng)記住,上下文的切換開(kāi)銷(xiāo)也很重要,如果你創(chuàng)建了太多的線(xiàn)程,CPU花費(fèi)在上下文的切換的時(shí)間將多于執(zhí)行程序的時(shí)間!